<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fr">
	<id>https://projets-se.plil.fr/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Vdetrez</id>
	<title>projets-se.plil.fr - Contributions [fr]</title>
	<link rel="self" type="application/atom+xml" href="https://projets-se.plil.fr/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Vdetrez"/>
	<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php/Sp%C3%A9cial:Contributions/Vdetrez"/>
	<updated>2026-09-20T16:20:53Z</updated>
	<subtitle>Contributions</subtitle>
	<generator>MediaWiki 1.39.1</generator>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=7238</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=7238"/>
		<updated>2025-01-25T12:14:55Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Schéma de fonctionnement de la mémoire */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PINOUT ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage du shield ===&lt;br /&gt;
&lt;br /&gt;
==== shield nu ====&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== shield fini ====&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Test du shield ===&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|679x679px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage carte mère ===&lt;br /&gt;
&lt;br /&gt;
==== carte mère nue ====&lt;br /&gt;
[[Fichier:PCB_carte_mère_nu.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== ajout ATmega 328p ====&lt;br /&gt;
[[Fichier:Brasage ATmega 328p carte mère.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== ajout ATmega 8U2 ====&lt;br /&gt;
[[Fichier:Carte mère G3 avec 8U2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== mise en lien des ATmega et correction de conception ====&lt;br /&gt;
La correction consiste en l'ajout d'un bouton reset et HWB pour l'ATmega8U2.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lien ATmega + correction.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== carte finale ====&lt;br /&gt;
[[Fichier:Carte mere finale detrez cart 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Tests ===&lt;br /&gt;
&lt;br /&gt;
==== Test de clignotement d'une LED (25ms) ====&lt;br /&gt;
[[Fichier:Test clignotement LED ATmega 328p .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Programmation des cartes ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
27/11/24 : pour le moment le µc atmega328p a réussi à être programmé par ISP en changeant les fuses grâce à avrdude. En revanche, impossible de programmer l'atmega8u2. Nous avons essayé de lui mettre un bootloader et de changer ses fuses mais c'est impossible dans les deux cas et la carte n'est donc pas détectée en USB.&lt;br /&gt;
&lt;br /&gt;
4/12/24 : nous avons réussi à mettre un bootloader dans le 8u2, en revanche nous n'arrivons toujours pas à programmer le 328p grâce au port USB. La cause : nous n'arrivons pas à burn le bootloader du 328p pour qu'il puisse recevoir des données via usb_série ...&lt;br /&gt;
&lt;br /&gt;
Solution trouvée : Nous avons changé le bootloader en mettant [https://github.com/Optiboot/optiboot/blob/master/optiboot/bootloaders/optiboot/optiboot_atmega328.hex celui-ci] (/usr/share/arduino/hardware/arduino/avr/bootloaders/optiboot) à la place pour augmenter la place de ce dernier. Maintenant le 328p peut être programmé grâce à l'USB.&lt;br /&gt;
&lt;br /&gt;
== Programmation ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Création mémoire sur carte SD ==&lt;br /&gt;
&lt;br /&gt;
=== Schéma de fonctionnement de la mémoire ===&lt;br /&gt;
[[Fichier:Gestion memoire sd.png|sans_cadre|770x770px]]&lt;br /&gt;
&lt;br /&gt;
=== Récupération des commandes de base ===&lt;br /&gt;
&lt;br /&gt;
Dans un premier temps, nous avons un programme qui permet à la carte de mère de reconnaitre 3 commandes: ls, rm et cp. Cela nous permettra par la suite de créer des fichiers, les supprimer et lire les fichiers présents dans le répertoire. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int main(){&lt;br /&gt;
    init_stdio();&lt;br /&gt;
    char data[Max_chaine],cmd[Max_chaine], arg1[Max_chaine],arg2[Max_chaine];&lt;br /&gt;
    while(1) {&lt;br /&gt;
        fgets(data,Max_chaine,stdin);&lt;br /&gt;
        fprintf(stdout,&amp;quot;\r&amp;quot;);&lt;br /&gt;
        fflush(stdout);&lt;br /&gt;
        int taille = sscanf(data,&amp;quot;%s %s %s&amp;quot;, cmd,arg1,arg2);&lt;br /&gt;
        if(taille != 0){&lt;br /&gt;
            switch(taille){&lt;br /&gt;
            case 1 :&lt;br /&gt;
                if(strcmp(cmd,&amp;quot;ls&amp;quot;) == 0) fprintf(stdout,&amp;quot;je suis un ls\n&amp;quot;);&lt;br /&gt;
                else fprintf(stdout,&amp;quot;je suis une fraude\n&amp;quot;);&lt;br /&gt;
                break;&lt;br /&gt;
            case 2 :&lt;br /&gt;
                if(strcmp(cmd,&amp;quot;rm&amp;quot;) == 0) fprintf(stdout,&amp;quot;je suis un rm\n mon arg est : %s \n&amp;quot;,arg1);&lt;br /&gt;
                else fprintf(stdout,&amp;quot;je suis une fraude\n&amp;quot;);&lt;br /&gt;
                break;&lt;br /&gt;
            case 3:&lt;br /&gt;
                if(strcmp(cmd,&amp;quot;cp&amp;quot;) == 0) {&lt;br /&gt;
                    fprintf(stdout,&amp;quot;je suis un cp\n&amp;quot;);&lt;br /&gt;
                    fprintf(stdout,&amp;quot;mon arg1 est : %s\n&amp;quot;,arg1);&lt;br /&gt;
                    fprintf(stdout,&amp;quot;mon arg2 est : %s\n&amp;quot;,arg2);}&lt;br /&gt;
                else fprintf(stdout,&amp;quot;je suis une fraude\n&amp;quot;);&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Lors de l'utilisation de minicom, le fgets ne s'exécute que lors d'un &amp;quot;/n&amp;quot;, cependant, un entrée sur le clavier correspond à un &amp;quot;/r&amp;quot;, nous avons donc converti chaque &amp;quot;/r&amp;quot; en &amp;quot;/n&amp;quot; dans notre fonction de scan pour fluidifier l'utilisation. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int get_serial_scanf(FILE *stream) {&lt;br /&gt;
static unsigned char nl=0;&lt;br /&gt;
if(stream==stdin){&lt;br /&gt;
  if(nl){ nl=0; return '\n'; }&lt;br /&gt;
  char c=get_serial();&lt;br /&gt;
  if(c=='\r') nl=1;&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
return _FDEV_EOF;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
À l'inverse, lors d'un fprintf, il est naturel en C de placer un &amp;quot;/n&amp;quot; à  la fin d'une chaine de caractère. Cependant, la carte mère à besoin d'un &amp;quot;\r&amp;quot; pour effectuer ce retour à la ligne. Nous avons donc converti chaque &amp;quot;\n&amp;quot; en &amp;quot;\r&amp;quot; dans notre fonction d'impression.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int send_serial_printf(char c,FILE *stream){&lt;br /&gt;
if(stream==stdout){&lt;br /&gt;
  if(c=='\n') send_serial('\r');&lt;br /&gt;
  send_serial(c);&lt;br /&gt;
}&lt;br /&gt;
return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Création d'un fichier ===&lt;br /&gt;
Nous sommes capable maintenant d'écrire le nom d'un fichier dans un bloc.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void createFile(SD_files* fichier){&lt;br /&gt;
    //write à 0 le nom puis les data pares&lt;br /&gt;
    uint8_t name[TAILLE_NOM];&lt;br /&gt;
    string_to_uint8_array(fichier-&amp;gt;name, name);&lt;br /&gt;
    int statut=writeBlock(&amp;amp;sd,LastFile,name);&lt;br /&gt;
    if(statut != 1) fprintf(stdout,&amp;quot;erreur lors du Write\n&amp;quot;);&lt;br /&gt;
    LastFile += NB_BLOCK_MAX;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Bilan de puissance ==&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Liens ==&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Gestion_memoire_sd.png&amp;diff=7237</id>
		<title>Fichier:Gestion memoire sd.png</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Gestion_memoire_sd.png&amp;diff=7237"/>
		<updated>2025-01-25T12:13:39Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;.&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=7091</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=7091"/>
		<updated>2025-01-08T11:06:53Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Schéma de fonctionnement de la mémoire */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PINOUT ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage du shield ===&lt;br /&gt;
&lt;br /&gt;
==== shield nu ====&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== shield fini ====&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Test du shield ===&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|679x679px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage carte mère ===&lt;br /&gt;
&lt;br /&gt;
==== carte mère nue ====&lt;br /&gt;
[[Fichier:PCB_carte_mère_nu.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== ajout ATmega 328p ====&lt;br /&gt;
[[Fichier:Brasage ATmega 328p carte mère.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== ajout ATmega 8U2 ====&lt;br /&gt;
[[Fichier:Carte mère G3 avec 8U2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== mise en lien des ATmega et correction de conception ====&lt;br /&gt;
La correction consiste en l'ajout d'un bouton reset et HWB pour l'ATmega8U2.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lien ATmega + correction.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== carte finale ====&lt;br /&gt;
[[Fichier:Carte mere finale detrez cart 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Tests ===&lt;br /&gt;
&lt;br /&gt;
==== Test de clignotement d'une LED (25ms) ====&lt;br /&gt;
[[Fichier:Test clignotement LED ATmega 328p .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Programmation des cartes ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
27/11/24 : pour le moment le µc atmega328p a réussi à être programmé par ISP en changeant les fuses grâce à avrdude. En revanche, impossible de programmer l'atmega8u2. Nous avons essayé de lui mettre un bootloader et de changer ses fuses mais c'est impossible dans les deux cas et la carte n'est donc pas détectée en USB.&lt;br /&gt;
&lt;br /&gt;
4/12/24 : nous avons réussi à mettre un bootloader dans le 8u2, en revanche nous n'arrivons toujours pas à programmer le 328p grâce au port USB. La cause : nous n'arrivons pas à burn le bootloader du 328p pour qu'il puisse recevoir des données via usb_série ...&lt;br /&gt;
&lt;br /&gt;
Solution trouvée : Nous avons changé le bootloader en mettant [https://github.com/Optiboot/optiboot/blob/master/optiboot/bootloaders/optiboot/optiboot_atmega328.hex celui-ci] (/usr/share/arduino/hardware/arduino/avr/bootloaders/optiboot) à la place pour augmenter la place de ce dernier. Maintenant le 328p peut être programmé grâce à l'USB.&lt;br /&gt;
&lt;br /&gt;
== Programmation ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Création mémoire sur carte SD ==&lt;br /&gt;
&lt;br /&gt;
=== Schéma de fonctionnement de la mémoire ===&lt;br /&gt;
(à modifier)&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Gestion memoire detrez cart.png|sans_cadre|770x770px]]&lt;br /&gt;
&lt;br /&gt;
=== Récupération des commandes de base ===&lt;br /&gt;
&lt;br /&gt;
Dans un premier temps, nous avons un programme qui permet à la carte de mère de reconnaitre 3 commandes: ls, rm et cp. Cela nous permettra par la suite de créer des fichiers, les supprimer et lire les fichiers présents dans le répertoire. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int main(){&lt;br /&gt;
    init_stdio();&lt;br /&gt;
    char data[Max_chaine],cmd[Max_chaine], arg1[Max_chaine],arg2[Max_chaine];&lt;br /&gt;
    while(1) {&lt;br /&gt;
        fgets(data,Max_chaine,stdin);&lt;br /&gt;
        fprintf(stdout,&amp;quot;\r&amp;quot;);&lt;br /&gt;
        fflush(stdout);&lt;br /&gt;
        int taille = sscanf(data,&amp;quot;%s %s %s&amp;quot;, cmd,arg1,arg2);&lt;br /&gt;
        if(taille != 0){&lt;br /&gt;
            switch(taille){&lt;br /&gt;
            case 1 :&lt;br /&gt;
                if(strcmp(cmd,&amp;quot;ls&amp;quot;) == 0) fprintf(stdout,&amp;quot;je suis un ls\n&amp;quot;);&lt;br /&gt;
                else fprintf(stdout,&amp;quot;je suis une fraude\n&amp;quot;);&lt;br /&gt;
                break;&lt;br /&gt;
            case 2 :&lt;br /&gt;
                if(strcmp(cmd,&amp;quot;rm&amp;quot;) == 0) fprintf(stdout,&amp;quot;je suis un rm\n mon arg est : %s \n&amp;quot;,arg1);&lt;br /&gt;
                else fprintf(stdout,&amp;quot;je suis une fraude\n&amp;quot;);&lt;br /&gt;
                break;&lt;br /&gt;
            case 3:&lt;br /&gt;
                if(strcmp(cmd,&amp;quot;cp&amp;quot;) == 0) {&lt;br /&gt;
                    fprintf(stdout,&amp;quot;je suis un cp\n&amp;quot;);&lt;br /&gt;
                    fprintf(stdout,&amp;quot;mon arg1 est : %s\n&amp;quot;,arg1);&lt;br /&gt;
                    fprintf(stdout,&amp;quot;mon arg2 est : %s\n&amp;quot;,arg2);}&lt;br /&gt;
                else fprintf(stdout,&amp;quot;je suis une fraude\n&amp;quot;);&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Lors de l'utilisation de minicom, le fgets ne s'exécute que lors d'un &amp;quot;/n&amp;quot;, cependant, un entrée sur le clavier correspond à un &amp;quot;/r&amp;quot;, nous avons donc converti chaque &amp;quot;/r&amp;quot; en &amp;quot;/n&amp;quot; dans notre fonction de scan pour fluidifier l'utilisation. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int get_serial_scanf(FILE *stream) {&lt;br /&gt;
static unsigned char nl=0;&lt;br /&gt;
if(stream==stdin){&lt;br /&gt;
  if(nl){ nl=0; return '\n'; }&lt;br /&gt;
  char c=get_serial();&lt;br /&gt;
  if(c=='\r') nl=1;&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
return _FDEV_EOF;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
À l'inverse, lors d'un fprintf, il est naturel en C de placer un &amp;quot;/n&amp;quot; à  la fin d'une chaine de caractère. Cependant, la carte mère à besoin d'un &amp;quot;\r&amp;quot; pour effectuer ce retour à la ligne. Nous avons donc converti chaque &amp;quot;\n&amp;quot; en &amp;quot;\r&amp;quot; dans notre fonction d'impression.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int send_serial_printf(char c,FILE *stream){&lt;br /&gt;
if(stream==stdout){&lt;br /&gt;
  if(c=='\n') send_serial('\r');&lt;br /&gt;
  send_serial(c);&lt;br /&gt;
}&lt;br /&gt;
return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Création d'un fichier ===&lt;br /&gt;
Nous sommes capable maintenant d'écrire le nom d'un fichier dans un bloc.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void createFile(SD_files* fichier){&lt;br /&gt;
    //write à 0 le nom puis les data pares&lt;br /&gt;
    uint8_t name[TAILLE_NOM];&lt;br /&gt;
    string_to_uint8_array(fichier-&amp;gt;name, name);&lt;br /&gt;
    int statut=writeBlock(&amp;amp;sd,LastFile,name);&lt;br /&gt;
    if(statut != 1) fprintf(stdout,&amp;quot;erreur lors du Write\n&amp;quot;);&lt;br /&gt;
    LastFile += NB_BLOCK_MAX;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Bilan de puissance ==&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Liens ==&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=7089</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=7089"/>
		<updated>2025-01-08T10:24:25Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Création mémoire sur carte SD */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PINOUT ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage du shield ===&lt;br /&gt;
&lt;br /&gt;
==== shield nu ====&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== shield fini ====&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Test du shield ===&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|679x679px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage carte mère ===&lt;br /&gt;
&lt;br /&gt;
==== carte mère nue ====&lt;br /&gt;
[[Fichier:PCB_carte_mère_nu.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== ajout ATmega 328p ====&lt;br /&gt;
[[Fichier:Brasage ATmega 328p carte mère.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== ajout ATmega 8U2 ====&lt;br /&gt;
[[Fichier:Carte mère G3 avec 8U2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== mise en lien des ATmega et correction de conception ====&lt;br /&gt;
La correction consiste en l'ajout d'un bouton reset et HWB pour l'ATmega8U2.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lien ATmega + correction.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== carte finale ====&lt;br /&gt;
[[Fichier:Carte mere finale detrez cart 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Tests ===&lt;br /&gt;
&lt;br /&gt;
==== Test de clignotement d'une LED (25ms) ====&lt;br /&gt;
[[Fichier:Test clignotement LED ATmega 328p .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Programmation des cartes ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
27/11/24 : pour le moment le µc atmega328p a réussi à être programmé par ISP en changeant les fuses grâce à avrdude. En revanche, impossible de programmer l'atmega8u2. Nous avons essayé de lui mettre un bootloader et de changer ses fuses mais c'est impossible dans les deux cas et la carte n'est donc pas détectée en USB.&lt;br /&gt;
&lt;br /&gt;
4/12/24 : nous avons réussi à mettre un bootloader dans le 8u2, en revanche nous n'arrivons toujours pas à programmer le 328p grâce au port USB. La cause : nous n'arrivons pas à burn le bootloader du 328p pour qu'il puisse recevoir des données via usb_série ...&lt;br /&gt;
&lt;br /&gt;
Solution trouvée : Nous avons changé le bootloader en mettant [https://github.com/Optiboot/optiboot/blob/master/optiboot/bootloaders/optiboot/optiboot_atmega328.hex celui-ci] (/usr/share/arduino/hardware/arduino/avr/bootloaders/optiboot) à la place pour augmenter la place de ce dernier. Maintenant le 328p peut être programmé grâce à l'USB.&lt;br /&gt;
&lt;br /&gt;
== Programmation ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Création mémoire sur carte SD ==&lt;br /&gt;
&lt;br /&gt;
=== Schéma de fonctionnement de la mémoire ===&lt;br /&gt;
[[Fichier:Gestion memoire detrez cart.png|sans_cadre|770x770px]]&lt;br /&gt;
&lt;br /&gt;
=== Récupération des commandes de base ===&lt;br /&gt;
&lt;br /&gt;
Dans un premier temps, nous avons un programme qui permet à la carte de mère de reconnaitre 3 commandes: ls, rm et cp. Cela nous permettra par la suite de créer des fichiers, les supprimer et lire les fichiers présents dans le répertoire. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int main(){&lt;br /&gt;
    init_stdio();&lt;br /&gt;
    char data[Max_chaine],cmd[Max_chaine], arg1[Max_chaine],arg2[Max_chaine];&lt;br /&gt;
    while(1) {&lt;br /&gt;
        fgets(data,Max_chaine,stdin);&lt;br /&gt;
        fprintf(stdout,&amp;quot;\r&amp;quot;);&lt;br /&gt;
        fflush(stdout);&lt;br /&gt;
        int taille = sscanf(data,&amp;quot;%s %s %s&amp;quot;, cmd,arg1,arg2);&lt;br /&gt;
        if(taille != 0){&lt;br /&gt;
            switch(taille){&lt;br /&gt;
            case 1 :&lt;br /&gt;
                if(strcmp(cmd,&amp;quot;ls&amp;quot;) == 0) fprintf(stdout,&amp;quot;je suis un ls\n&amp;quot;);&lt;br /&gt;
                else fprintf(stdout,&amp;quot;je suis une fraude\n&amp;quot;);&lt;br /&gt;
                break;&lt;br /&gt;
            case 2 :&lt;br /&gt;
                if(strcmp(cmd,&amp;quot;rm&amp;quot;) == 0) fprintf(stdout,&amp;quot;je suis un rm\n mon arg est : %s \n&amp;quot;,arg1);&lt;br /&gt;
                else fprintf(stdout,&amp;quot;je suis une fraude\n&amp;quot;);&lt;br /&gt;
                break;&lt;br /&gt;
            case 3:&lt;br /&gt;
                if(strcmp(cmd,&amp;quot;cp&amp;quot;) == 0) {&lt;br /&gt;
                    fprintf(stdout,&amp;quot;je suis un cp\n&amp;quot;);&lt;br /&gt;
                    fprintf(stdout,&amp;quot;mon arg1 est : %s\n&amp;quot;,arg1);&lt;br /&gt;
                    fprintf(stdout,&amp;quot;mon arg2 est : %s\n&amp;quot;,arg2);}&lt;br /&gt;
                else fprintf(stdout,&amp;quot;je suis une fraude\n&amp;quot;);&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Lors de l'utilisation de minicom, le fgets ne s'exécute que lors d'un &amp;quot;/n&amp;quot;, cependant, un entrée sur le clavier correspond à un &amp;quot;/r&amp;quot;, nous avons donc converti chaque &amp;quot;/r&amp;quot; en &amp;quot;/n&amp;quot; dans notre fonction de scan pour fluidifier l'utilisation. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int get_serial_scanf(FILE *stream) {&lt;br /&gt;
static unsigned char nl=0;&lt;br /&gt;
if(stream==stdin){&lt;br /&gt;
  if(nl){ nl=0; return '\n'; }&lt;br /&gt;
  char c=get_serial();&lt;br /&gt;
  if(c=='\r') nl=1;&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
return _FDEV_EOF;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
À l'inverse, lors d'un fprintf, il est naturel en C de placer un &amp;quot;/n&amp;quot; à  la fin d'une chaine de caractère. Cependant, la carte mère à besoin d'un &amp;quot;\r&amp;quot; pour effectuer ce retour à la ligne. Nous avons donc converti chaque &amp;quot;\n&amp;quot; en &amp;quot;\r&amp;quot; dans notre fonction d'impression.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int send_serial_printf(char c,FILE *stream){&lt;br /&gt;
if(stream==stdout){&lt;br /&gt;
  if(c=='\n') send_serial('\r');&lt;br /&gt;
  send_serial(c);&lt;br /&gt;
}&lt;br /&gt;
return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Création d'un fichier ===&lt;br /&gt;
Nous sommes capable maintenant d'écrire le nom d'un fichier dans un bloc.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void createFile(SD_files* fichier){&lt;br /&gt;
    //write à 0 le nom puis les data pares&lt;br /&gt;
    uint8_t name[TAILLE_NOM];&lt;br /&gt;
    string_to_uint8_array(fichier-&amp;gt;name, name);&lt;br /&gt;
    int statut=writeBlock(&amp;amp;sd,LastFile,name);&lt;br /&gt;
    if(statut != 1) fprintf(stdout,&amp;quot;erreur lors du Write\n&amp;quot;);&lt;br /&gt;
    LastFile += NB_BLOCK_MAX;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Bilan de puissance ==&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Liens ==&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Gestion_memoire_detrez_cart.png&amp;diff=7088</id>
		<title>Fichier:Gestion memoire detrez cart.png</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Gestion_memoire_detrez_cart.png&amp;diff=7088"/>
		<updated>2025-01-08T10:21:55Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;.&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=7087</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=7087"/>
		<updated>2025-01-07T14:56:59Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PINOUT ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage du shield ===&lt;br /&gt;
&lt;br /&gt;
==== shield nu ====&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== shield fini ====&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Test du shield ===&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|679x679px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage carte mère ===&lt;br /&gt;
&lt;br /&gt;
==== carte mère nue ====&lt;br /&gt;
[[Fichier:PCB_carte_mère_nu.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== ajout ATmega 328p ====&lt;br /&gt;
[[Fichier:Brasage ATmega 328p carte mère.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== ajout ATmega 8U2 ====&lt;br /&gt;
[[Fichier:Carte mère G3 avec 8U2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== mise en lien des ATmega et correction de conception ====&lt;br /&gt;
La correction consiste en l'ajout d'un bouton reset et HWB pour l'ATmega8U2.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lien ATmega + correction.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== carte finale ====&lt;br /&gt;
[[Fichier:Carte mere finale detrez cart 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Tests ===&lt;br /&gt;
&lt;br /&gt;
==== Test de clignotement d'une LED (25ms) ====&lt;br /&gt;
[[Fichier:Test clignotement LED ATmega 328p .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Programmation des cartes ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
27/11/24 : pour le moment le µc atmega328p a réussi à être programmé par ISP en changeant les fuses grâce à avrdude. En revanche, impossible de programmer l'atmega8u2. Nous avons essayé de lui mettre un bootloader et de changer ses fuses mais c'est impossible dans les deux cas et la carte n'est donc pas détectée en USB.&lt;br /&gt;
&lt;br /&gt;
4/12/24 : nous avons réussi à mettre un bootloader dans le 8u2, en revanche nous n'arrivons toujours pas à programmer le 328p grâce au port USB. La cause : nous n'arrivons pas à burn le bootloader du 328p pour qu'il puisse recevoir des données via usb_série ...&lt;br /&gt;
&lt;br /&gt;
Solution trouvée : Nous avons changé le bootloader en mettant [https://github.com/Optiboot/optiboot/blob/master/optiboot/bootloaders/optiboot/optiboot_atmega328.hex celui-ci] (/usr/share/arduino/hardware/arduino/avr/bootloaders/optiboot) à la place pour augmenter la place de ce dernier. Maintenant le 328p peut être programmé grâce à l'USB.&lt;br /&gt;
&lt;br /&gt;
== Programmation ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Création mémoire sur carte SD ==&lt;br /&gt;
Dans un premier temps, nous avons un programme qui permet à la carte de mère de reconnaitre 3 commandes: ls, rm et cp. Cela nous permettra par la suite de créer des fichiers, les supprimer et lire les fichiers présents dans le répertoire. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int main(){&lt;br /&gt;
    init_stdio();&lt;br /&gt;
    char data[Max_chaine],cmd[Max_chaine], arg1[Max_chaine],arg2[Max_chaine];&lt;br /&gt;
    while(1) {&lt;br /&gt;
        fgets(data,Max_chaine,stdin);&lt;br /&gt;
        fprintf(stdout,&amp;quot;\r&amp;quot;);&lt;br /&gt;
        fflush(stdout);&lt;br /&gt;
        int taille = sscanf(data,&amp;quot;%s %s %s&amp;quot;, cmd,arg1,arg2);&lt;br /&gt;
        if(taille != 0){&lt;br /&gt;
            switch(taille){&lt;br /&gt;
            case 1 :&lt;br /&gt;
                if(strcmp(cmd,&amp;quot;ls&amp;quot;) == 0) fprintf(stdout,&amp;quot;je suis un ls\n&amp;quot;);&lt;br /&gt;
                else fprintf(stdout,&amp;quot;je suis une fraude\n&amp;quot;);&lt;br /&gt;
                break;&lt;br /&gt;
            case 2 :&lt;br /&gt;
                if(strcmp(cmd,&amp;quot;rm&amp;quot;) == 0) fprintf(stdout,&amp;quot;je suis un rm\n mon arg est : %s \n&amp;quot;,arg1);&lt;br /&gt;
                else fprintf(stdout,&amp;quot;je suis une fraude\n&amp;quot;);&lt;br /&gt;
                break;&lt;br /&gt;
            case 3:&lt;br /&gt;
                if(strcmp(cmd,&amp;quot;cp&amp;quot;) == 0) {&lt;br /&gt;
                    fprintf(stdout,&amp;quot;je suis un cp\n&amp;quot;);&lt;br /&gt;
                    fprintf(stdout,&amp;quot;mon arg1 est : %s\n&amp;quot;,arg1);&lt;br /&gt;
                    fprintf(stdout,&amp;quot;mon arg2 est : %s\n&amp;quot;,arg2);}&lt;br /&gt;
                else fprintf(stdout,&amp;quot;je suis une fraude\n&amp;quot;);&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Lors de l'utilisation de minicom, le fgets ne s'exécute que lors d'un &amp;quot;/n&amp;quot;, cependant, un entrée sur le clavier correspond à un &amp;quot;/r&amp;quot;, nous avons donc converti chaque &amp;quot;/r&amp;quot; en &amp;quot;/n&amp;quot; dans notre fonction de scan pour fluidifier l'utilisation. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int get_serial_scanf(FILE *stream) {&lt;br /&gt;
static unsigned char nl=0;&lt;br /&gt;
if(stream==stdin){&lt;br /&gt;
  if(nl){ nl=0; return '\n'; }&lt;br /&gt;
  char c=get_serial();&lt;br /&gt;
  if(c=='\r') nl=1;&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
return _FDEV_EOF;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
À l'inverse, lors d'un fprintf, il est naturel en C de placer un &amp;quot;/n&amp;quot; à  la fin d'une chaine de caractère. Cependant, la carte mère à besoin d'un &amp;quot;\r&amp;quot; pour effectuer ce retour à la ligne. Nous avons donc converti chaque &amp;quot;\n&amp;quot; en &amp;quot;\r&amp;quot; dans notre fonction d'impression.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int send_serial_printf(char c,FILE *stream){&lt;br /&gt;
if(stream==stdout){&lt;br /&gt;
  if(c=='\n') send_serial('\r');&lt;br /&gt;
  send_serial(c);&lt;br /&gt;
}&lt;br /&gt;
return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Création d'un fichier ===&lt;br /&gt;
Nous sommes capable maintenant d'écrire le nom d'un fichier dans un bloc.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void createFile(SD_files* fichier){&lt;br /&gt;
    //write à 0 le nom puis les data pares&lt;br /&gt;
    uint8_t name[TAILLE_NOM];&lt;br /&gt;
    string_to_uint8_array(fichier-&amp;gt;name, name);&lt;br /&gt;
    int statut=writeBlock(&amp;amp;sd,LastFile,name);&lt;br /&gt;
    if(statut != 1) fprintf(stdout,&amp;quot;erreur lors du Write\n&amp;quot;);&lt;br /&gt;
    LastFile += NB_BLOCK_MAX;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Bilan de puissance ==&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Liens ==&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=7086</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=7086"/>
		<updated>2025-01-07T14:55:38Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Création mémoire sur carte SD */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PINOUT ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage du shield ===&lt;br /&gt;
&lt;br /&gt;
==== shield nu ====&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== shield fini ====&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Test du shield ===&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|679x679px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage carte mère ===&lt;br /&gt;
&lt;br /&gt;
==== carte mère nue ====&lt;br /&gt;
[[Fichier:PCB_carte_mère_nu.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== ajout ATmega 328p ====&lt;br /&gt;
[[Fichier:Brasage ATmega 328p carte mère.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== ajout ATmega 8U2 ====&lt;br /&gt;
[[Fichier:Carte mère G3 avec 8U2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== mise en lien des ATmega et correction de conception ====&lt;br /&gt;
La correction consiste en l'ajout d'un bouton reset et HWB pour l'ATmega8U2.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lien ATmega + correction.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== carte finale ====&lt;br /&gt;
[[Fichier:Carte mere finale detrez cart 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Tests ===&lt;br /&gt;
&lt;br /&gt;
==== Test de clignotement d'une LED (25ms) ====&lt;br /&gt;
[[Fichier:Test clignotement LED ATmega 328p .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Programmation des cartes ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
27/11/24 : pour le moment le µc atmega328p a réussi à être programmé par ISP en changeant les fuses grâce à avrdude. En revanche, impossible de programmer l'atmega8u2. Nous avons essayé de lui mettre un bootloader et de changer ses fuses mais c'est impossible dans les deux cas et la carte n'est donc pas détectée en USB.&lt;br /&gt;
&lt;br /&gt;
4/12/24 : nous avons réussi à mettre un bootloader dans le 8u2, en revanche nous n'arrivons toujours pas à programmer le 328p grâce au port USB. La cause : nous n'arrivons pas à burn le bootloader du 328p pour qu'il puisse recevoir des données via usb_série ...&lt;br /&gt;
&lt;br /&gt;
Solution trouvée : Nous avons changé le bootloader en mettant [https://github.com/Optiboot/optiboot/blob/master/optiboot/bootloaders/optiboot/optiboot_atmega328.hex celui-ci] (/usr/share/arduino/hardware/arduino/avr/bootloaders/optiboot) à la place pour augmenter la place de ce dernier. Maintenant le 328p peut être programmé grâce à l'USB.&lt;br /&gt;
&lt;br /&gt;
== Programmation ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Création mémoire sur carte SD ==&lt;br /&gt;
Dans un premier temps, nous avons un programme qui permet à la carte de mère de reconnaitre 3 commandes: ls, rm et cp. Cela nous permettra par la suite de créer des fichiers, les supprimer et lire les fichiers présents dans le répertoire. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int main(){&lt;br /&gt;
    init_stdio();&lt;br /&gt;
    char data[Max_chaine],cmd[Max_chaine], arg1[Max_chaine],arg2[Max_chaine];&lt;br /&gt;
    while(1) {&lt;br /&gt;
        fgets(data,Max_chaine,stdin);&lt;br /&gt;
        fprintf(stdout,&amp;quot;\r&amp;quot;);&lt;br /&gt;
        fflush(stdout);&lt;br /&gt;
        int taille = sscanf(data,&amp;quot;%s %s %s&amp;quot;, cmd,arg1,arg2);&lt;br /&gt;
        if(taille != 0){&lt;br /&gt;
            switch(taille){&lt;br /&gt;
            case 1 :&lt;br /&gt;
                if(strcmp(cmd,&amp;quot;ls&amp;quot;) == 0) fprintf(stdout,&amp;quot;je suis un ls\n&amp;quot;);&lt;br /&gt;
                else fprintf(stdout,&amp;quot;je suis une fraude\n&amp;quot;);&lt;br /&gt;
                break;&lt;br /&gt;
            case 2 :&lt;br /&gt;
                if(strcmp(cmd,&amp;quot;rm&amp;quot;) == 0) fprintf(stdout,&amp;quot;je suis un rm\n mon arg est : %s \n&amp;quot;,arg1);&lt;br /&gt;
                else fprintf(stdout,&amp;quot;je suis une fraude\n&amp;quot;);&lt;br /&gt;
                break;&lt;br /&gt;
            case 3:&lt;br /&gt;
                if(strcmp(cmd,&amp;quot;cp&amp;quot;) == 0) {&lt;br /&gt;
                    fprintf(stdout,&amp;quot;je suis un cp\n&amp;quot;);&lt;br /&gt;
                    fprintf(stdout,&amp;quot;mon arg1 est : %s\n&amp;quot;,arg1);&lt;br /&gt;
                    fprintf(stdout,&amp;quot;mon arg2 est : %s\n&amp;quot;,arg2);}&lt;br /&gt;
                else fprintf(stdout,&amp;quot;je suis une fraude\n&amp;quot;);&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Lors de l'utilisation de minicom, le fgets ne s'exécute que lors d'un &amp;quot;/n&amp;quot;, cependant, un entrée sur le clavier correspond à un &amp;quot;/r&amp;quot;, nous avons donc converti chaque &amp;quot;/r&amp;quot; en &amp;quot;/n&amp;quot; dans notre fonction de scan pour fluidifier l'utilisation. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int get_serial_scanf(FILE *stream) {&lt;br /&gt;
static unsigned char nl=0;&lt;br /&gt;
if(stream==stdin){&lt;br /&gt;
  if(nl){ nl=0; return '\n'; }&lt;br /&gt;
  char c=get_serial();&lt;br /&gt;
  if(c=='\r') nl=1;&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
return _FDEV_EOF;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
À l'inverse, lors d'un fprintf, il est naturel en C de placer un &amp;quot;/n&amp;quot; à  la fin d'une chaine de caractère. Cependant, la carte mère à besoin d'un &amp;quot;\r&amp;quot; pour effectuer ce retour à la ligne. Nous avons donc converti chaque &amp;quot;\n&amp;quot; en &amp;quot;\r&amp;quot; dans notre fonction d'impression.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int send_serial_printf(char c,FILE *stream){&lt;br /&gt;
if(stream==stdout){&lt;br /&gt;
  if(c=='\n') send_serial('\r');&lt;br /&gt;
  send_serial(c);&lt;br /&gt;
}&lt;br /&gt;
return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Création d'un fichier ===&lt;br /&gt;
Nous sommes capable maintenant d'écrire le nom d'un fichier dans un bloc.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void createFile(SD_files* fichier){&lt;br /&gt;
    //write à 0 le nom puis les data pares&lt;br /&gt;
    uint8_t name[TAILLE_NOM];&lt;br /&gt;
    string_to_uint8_array(fichier-&amp;gt;name, name);&lt;br /&gt;
    int statut=writeBlock(&amp;amp;sd,LastFile,name);&lt;br /&gt;
    if(statut != 1) fprintf(stdout,&amp;quot;erreur lors du Write\n&amp;quot;);&lt;br /&gt;
    LastFile += NB_BLOCK_MAX;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Bilan de puissance ==&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Liens ==&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=7053</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=7053"/>
		<updated>2025-01-06T11:03:51Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Création mémoire sur carte SD */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PINOUT ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage du shield ===&lt;br /&gt;
&lt;br /&gt;
==== shield nu ====&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== shield fini ====&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Test du shield ===&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|679x679px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage carte mère ===&lt;br /&gt;
&lt;br /&gt;
==== carte mère nue ====&lt;br /&gt;
[[Fichier:PCB_carte_mère_nu.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== ajout ATmega 328p ====&lt;br /&gt;
[[Fichier:Brasage ATmega 328p carte mère.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== ajout ATmega 8U2 ====&lt;br /&gt;
[[Fichier:Carte mère G3 avec 8U2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== mise en lien des ATmega et correction de conception ====&lt;br /&gt;
La correction consiste en l'ajout d'un bouton reset et HWB pour l'ATmega8U2.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lien ATmega + correction.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== carte finale ====&lt;br /&gt;
[[Fichier:Carte mere finale detrez cart 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Tests ===&lt;br /&gt;
&lt;br /&gt;
==== Test de clignotement d'une LED (25ms) ====&lt;br /&gt;
[[Fichier:Test clignotement LED ATmega 328p .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Programmation des cartes ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
27/11/24 : pour le moment le µc atmega328p a réussi à être programmé par ISP en changeant les fuses grâce à avrdude. En revanche, impossible de programmer l'atmega8u2. Nous avons essayé de lui mettre un bootloader et de changer ses fuses mais c'est impossible dans les deux cas et la carte n'est donc pas détectée en USB.&lt;br /&gt;
&lt;br /&gt;
4/12/24 : nous avons réussi à mettre un bootloader dans le 8u2, en revanche nous n'arrivons toujours pas à programmer le 328p grâce au port USB. La cause : nous n'arrivons pas à burn le bootloader du 328p pour qu'il puisse recevoir des données via usb_série ...&lt;br /&gt;
&lt;br /&gt;
Solution trouvée : Nous avons changé le bootloader en mettant [https://github.com/Optiboot/optiboot/blob/master/optiboot/bootloaders/optiboot/optiboot_atmega328.hex celui-ci] (/usr/share/arduino/hardware/arduino/avr/bootloaders/optiboot) à la place pour augmenter la place de ce dernier. Maintenant le 328p peut être programmé grâce à l'USB.&lt;br /&gt;
&lt;br /&gt;
== Programmation ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Création mémoire sur carte SD ==&lt;br /&gt;
Dans un premier temps, nous avons un programme qui permet à la carte de mère de reconnaitre 3 commandes: ls, rm et cp. Cela nous permettra par la suite de créer des fichiers, les supprimer et lire les fichiers présents dans le répertoire. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int main(){&lt;br /&gt;
    init_stdio();&lt;br /&gt;
    char data[Max_chaine],cmd[Max_chaine], arg1[Max_chaine],arg2[Max_chaine];&lt;br /&gt;
    while(1) {&lt;br /&gt;
        fgets(data,Max_chaine,stdin);&lt;br /&gt;
        fprintf(stdout,&amp;quot;\r&amp;quot;);&lt;br /&gt;
        fflush(stdout);&lt;br /&gt;
        int taille = sscanf(data,&amp;quot;%s %s %s&amp;quot;, cmd,arg1,arg2);&lt;br /&gt;
        if(taille != 0){&lt;br /&gt;
            switch(taille){&lt;br /&gt;
            case 1 :&lt;br /&gt;
                if(strcmp(cmd,&amp;quot;ls&amp;quot;) == 0) fprintf(stdout,&amp;quot;je suis un ls\n&amp;quot;);&lt;br /&gt;
                else fprintf(stdout,&amp;quot;je suis une fraude\n&amp;quot;);&lt;br /&gt;
                break;&lt;br /&gt;
            case 2 :&lt;br /&gt;
                if(strcmp(cmd,&amp;quot;rm&amp;quot;) == 0) fprintf(stdout,&amp;quot;je suis un rm\n mon arg est : %s \n&amp;quot;,arg1);&lt;br /&gt;
                else fprintf(stdout,&amp;quot;je suis une fraude\n&amp;quot;);&lt;br /&gt;
                break;&lt;br /&gt;
            case 3:&lt;br /&gt;
                if(strcmp(cmd,&amp;quot;cp&amp;quot;) == 0) {&lt;br /&gt;
                    fprintf(stdout,&amp;quot;je suis un cp\n&amp;quot;);&lt;br /&gt;
                    fprintf(stdout,&amp;quot;mon arg1 est : %s\n&amp;quot;,arg1);&lt;br /&gt;
                    fprintf(stdout,&amp;quot;mon arg2 est : %s\n&amp;quot;,arg2);}&lt;br /&gt;
                else fprintf(stdout,&amp;quot;je suis une fraude\n&amp;quot;);&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Lors de l'utilisation de minicom, le fgets ne s'exécute que lors d'un &amp;quot;/n&amp;quot;, cependant, un entrée sur le clavier correspond à un &amp;quot;/r&amp;quot;, nous avons donc converti chaque &amp;quot;/r&amp;quot; en &amp;quot;/n&amp;quot; dans notre fonction de scan pour fluidifier l'utilisation. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int get_serial_scanf(FILE *stream) {&lt;br /&gt;
static unsigned char nl=0;&lt;br /&gt;
if(stream==stdin){&lt;br /&gt;
  if(nl){ nl=0; return '\n'; }&lt;br /&gt;
  char c=get_serial();&lt;br /&gt;
  if(c=='\r') nl=1;&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
return _FDEV_EOF;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
À l'inverse, lors d'un fprintf, il est naturel en C de placer un &amp;quot;/n&amp;quot; à  la fin d'une chaine de caractère. Cependant, la carte mère à besoin d'un &amp;quot;\r&amp;quot; pour effectuer ce retour à la ligne. Nous avons donc converti chaque &amp;quot;\n&amp;quot; en &amp;quot;\r&amp;quot; dans notre fonction d'impression.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int send_serial_printf(char c,FILE *stream){&lt;br /&gt;
if(stream==stdout){&lt;br /&gt;
  if(c=='\n') send_serial('\r');&lt;br /&gt;
  send_serial(c);&lt;br /&gt;
}&lt;br /&gt;
return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Bilan de puissance ==&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Liens ==&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=7052</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=7052"/>
		<updated>2025-01-06T09:35:40Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Programmation ordonnanceur */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PINOUT ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage du shield ===&lt;br /&gt;
&lt;br /&gt;
==== shield nu ====&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== shield fini ====&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Test du shield ===&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|679x679px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage carte mère ===&lt;br /&gt;
&lt;br /&gt;
==== carte mère nue ====&lt;br /&gt;
[[Fichier:PCB_carte_mère_nu.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== ajout ATmega 328p ====&lt;br /&gt;
[[Fichier:Brasage ATmega 328p carte mère.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== ajout ATmega 8U2 ====&lt;br /&gt;
[[Fichier:Carte mère G3 avec 8U2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== mise en lien des ATmega et correction de conception ====&lt;br /&gt;
La correction consiste en l'ajout d'un bouton reset et HWB pour l'ATmega8U2.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lien ATmega + correction.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== carte finale ====&lt;br /&gt;
[[Fichier:Carte mere finale detrez cart 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Tests ===&lt;br /&gt;
&lt;br /&gt;
==== Test de clignotement d'une LED (25ms) ====&lt;br /&gt;
[[Fichier:Test clignotement LED ATmega 328p .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Programmation des cartes ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
27/11/24 : pour le moment le µc atmega328p a réussi à être programmé par ISP en changeant les fuses grâce à avrdude. En revanche, impossible de programmer l'atmega8u2. Nous avons essayé de lui mettre un bootloader et de changer ses fuses mais c'est impossible dans les deux cas et la carte n'est donc pas détectée en USB.&lt;br /&gt;
&lt;br /&gt;
4/12/24 : nous avons réussi à mettre un bootloader dans le 8u2, en revanche nous n'arrivons toujours pas à programmer le 328p grâce au port USB. La cause : nous n'arrivons pas à burn le bootloader du 328p pour qu'il puisse recevoir des données via usb_série ...&lt;br /&gt;
&lt;br /&gt;
Solution trouvée : Nous avons changé le bootloader en mettant [https://github.com/Optiboot/optiboot/blob/master/optiboot/bootloaders/optiboot/optiboot_atmega328.hex celui-ci] (/usr/share/arduino/hardware/arduino/avr/bootloaders/optiboot) à la place pour augmenter la place de ce dernier. Maintenant le 328p peut être programmé grâce à l'USB.&lt;br /&gt;
&lt;br /&gt;
== Programmation ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Création mémoire sur carte SD ==&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Bilan de puissance ==&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Liens ==&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6960</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6960"/>
		<updated>2024-12-16T13:10:58Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* mise en lien des ATmega et correction de conception */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PINOUT ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage du shield ===&lt;br /&gt;
&lt;br /&gt;
==== shield nu ====&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== shield fini ====&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Test du shield ===&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|679x679px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage carte mère ===&lt;br /&gt;
&lt;br /&gt;
==== carte mère nue ====&lt;br /&gt;
[[Fichier:PCB_carte_mère_nu.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== ajout ATmega 328p ====&lt;br /&gt;
[[Fichier:Brasage ATmega 328p carte mère.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== ajout ATmega 8U2 ====&lt;br /&gt;
[[Fichier:Carte mère G3 avec 8U2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== mise en lien des ATmega et correction de conception ====&lt;br /&gt;
La correction consiste en l'ajout d'un bouton reset et HWB pour l'ATmega8U2.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lien ATmega + correction.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== carte finale ====&lt;br /&gt;
[[Fichier:Carte mere finale detrez cart 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Tests ===&lt;br /&gt;
&lt;br /&gt;
==== Test de clignotement d'une LED (25ms) ====&lt;br /&gt;
[[Fichier:Test clignotement LED ATmega 328p .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Programmation des cartes ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
27/11/24 : pour le moment le µc atmega328p a réussi à être programmé par ISP en changeant les fuses grâce à avrdude. En revanche, impossible de programmer l'atmega8u2. Nous avons essayé de lui mettre un bootloader et de changer ses fuses mais c'est impossible dans les deux cas et la carte n'est donc pas détectée en USB.&lt;br /&gt;
&lt;br /&gt;
4/12/24 : nous avons réussi à mettre un bootloader dans le 8u2, en revanche nous n'arrivons toujours pas à programmer le 328p grâce au port USB. La cause : nous n'arrivons pas à burn le bootloader du 328p pour qu'il puisse recevoir des données via usb_série ...&lt;br /&gt;
&lt;br /&gt;
Solution trouvée : Nous avons changé le bootloader en mettant [https://github.com/Optiboot/optiboot/blob/master/optiboot/bootloaders/optiboot/optiboot_atmega328.hex celui-ci] (/usr/share/arduino/hardware/arduino/avr/bootloaders/optiboot) à la place pour augmenter la place de ce dernier. Maintenant le 328p peut être programmé grâce à l'USB.&lt;br /&gt;
&lt;br /&gt;
== Programmation ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Bilan de puissance ==&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Liens ==&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Carte_mere_finale_detrez_cart_2.jpg&amp;diff=6959</id>
		<title>Fichier:Carte mere finale detrez cart 2.jpg</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Carte_mere_finale_detrez_cart_2.jpg&amp;diff=6959"/>
		<updated>2024-12-16T13:09:45Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;.&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Carte_m%C3%A8re_finale_detrez_cart.jpg&amp;diff=6958</id>
		<title>Fichier:Carte mère finale detrez cart.jpg</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Carte_m%C3%A8re_finale_detrez_cart.jpg&amp;diff=6958"/>
		<updated>2024-12-16T13:07:11Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;.&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6927</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6927"/>
		<updated>2024-12-04T09:34:52Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Brasage carte mère */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PINOUT ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage du shield ===&lt;br /&gt;
&lt;br /&gt;
==== shield nu ====&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== shield fini ====&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Test du shield ===&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|679x679px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage carte mère ===&lt;br /&gt;
&lt;br /&gt;
==== carte mère nue ====&lt;br /&gt;
[[Fichier:PCB_carte_mère_nu.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== ajout ATmega 328p ====&lt;br /&gt;
[[Fichier:Brasage ATmega 328p carte mère.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== ajout ATmega 8U2 ====&lt;br /&gt;
[[Fichier:Carte mère G3 avec 8U2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== mise en lien des ATmega et correction de conception ====&lt;br /&gt;
La correction consiste en l'ajout d'un bouton reset et HWB pour l'ATmega8U2.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lien ATmega + correction.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Tests ===&lt;br /&gt;
&lt;br /&gt;
==== Test de clignotement d'une LED (25ms) ====&lt;br /&gt;
[[Fichier:Test clignotement LED ATmega 328p .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Programmation des cartes ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
27/11/24 : pour le moment le µc atmega328p a réussi à être programmé par ISP en changeant les fuses grâce à avrdude. En revanche, impossible de programmer l'atmega8u2. Nous avons essayé de lui mettre un bootloader et de changer ses fuses mais c'est impossible dans les deux cas et la carte n'est donc pas détectée en USB.&lt;br /&gt;
&lt;br /&gt;
== Programmation ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Bilan de puissance ==&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Liens ==&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Lien_ATmega_%2B_correction.jpg&amp;diff=6926</id>
		<title>Fichier:Lien ATmega + correction.jpg</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Lien_ATmega_%2B_correction.jpg&amp;diff=6926"/>
		<updated>2024-12-04T09:34:13Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;.&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6881</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6881"/>
		<updated>2024-11-27T10:27:50Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Brasage carte mère */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PINOUT ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage du shield ===&lt;br /&gt;
&lt;br /&gt;
==== shield nu ====&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== shield fini ====&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Test du shield ===&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|679x679px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage carte mère ===&lt;br /&gt;
&lt;br /&gt;
==== carte mère nue ====&lt;br /&gt;
[[Fichier:PCB_carte_mère_nu.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== ajout ATmega 328p ====&lt;br /&gt;
[[Fichier:Brasage ATmega 328p carte mère.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== ajout ATmega 8U2 ====&lt;br /&gt;
[[Fichier:Carte mère G3 avec 8U2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Tests ===&lt;br /&gt;
&lt;br /&gt;
==== Test de clignotement d'une LED (25ms) ====&lt;br /&gt;
[[Fichier:Test clignotement LED ATmega 328p .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Programmation ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Bilan de puissance ==&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Liens ==&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Carte_m%C3%A8re_G3_avec_8U2.jpg&amp;diff=6880</id>
		<title>Fichier:Carte mère G3 avec 8U2.jpg</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Carte_m%C3%A8re_G3_avec_8U2.jpg&amp;diff=6880"/>
		<updated>2024-11-27T10:26:52Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;.&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6860</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6860"/>
		<updated>2024-11-20T10:58:04Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Exemple d'utilisation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PINOUT ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage du shield ===&lt;br /&gt;
&lt;br /&gt;
==== shield nu ====&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== shield fini ====&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Test du shield ===&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|679x679px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage carte mère ===&lt;br /&gt;
&lt;br /&gt;
==== carte mère nue ====&lt;br /&gt;
[[Fichier:PCB_carte_mère_nu.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== carte mère avec ATmega 328p ====&lt;br /&gt;
[[Fichier:Brasage ATmega 328p carte mère.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Tests ===&lt;br /&gt;
&lt;br /&gt;
==== Test de clignotement d'une LED (25ms) ====&lt;br /&gt;
[[Fichier:Test clignotement LED ATmega 328p .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Programmation ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Bilan de puissance ==&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Liens ==&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Test_clignotement_LED_ATmega_328p_.mp4&amp;diff=6858</id>
		<title>Fichier:Test clignotement LED ATmega 328p .mp4</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Test_clignotement_LED_ATmega_328p_.mp4&amp;diff=6858"/>
		<updated>2024-11-20T10:56:30Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;.&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6821</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6821"/>
		<updated>2024-11-20T09:28:23Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Réalisation carte mère */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PINOUT ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage du shield ===&lt;br /&gt;
&lt;br /&gt;
==== shield nu ====&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== shield fini ====&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Test du shield ===&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|679x679px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage carte mère ===&lt;br /&gt;
&lt;br /&gt;
==== carte mère nue ====&lt;br /&gt;
[[Fichier:PCB_carte_mère_nu.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== carte mère avec ATmega 328p ====&lt;br /&gt;
[[Fichier:Brasage ATmega 328p carte mère.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
== Programmation ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Bilan de puissance ==&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Liens ==&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6773</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6773"/>
		<updated>2024-11-19T14:17:14Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* carte mère avec ATmega 328p */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PINOUT ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage du shield ===&lt;br /&gt;
&lt;br /&gt;
==== shield nu ====&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== shield fini ====&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Test du shield ===&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|679x679px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage carte mère ===&lt;br /&gt;
&lt;br /&gt;
==== carte mère nue ====&lt;br /&gt;
[[Fichier:PCB_carte_mère_nu.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== carte mère avec ATmega 328p ====&lt;br /&gt;
[[Fichier:Brasage ATmega 328p carte mère.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Programmation ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Bilan de puissance ==&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Liens ==&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Brasage_ATmega_328p_carte_m%C3%A8re.jpg&amp;diff=6772</id>
		<title>Fichier:Brasage ATmega 328p carte mère.jpg</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Brasage_ATmega_328p_carte_m%C3%A8re.jpg&amp;diff=6772"/>
		<updated>2024-11-19T14:16:49Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;.&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6770</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6770"/>
		<updated>2024-11-19T13:52:16Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* carte mère nue */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PINOUT ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage du shield ===&lt;br /&gt;
&lt;br /&gt;
==== shield nu ====&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== shield fini ====&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Test du shield ===&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|679x679px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage carte mère ===&lt;br /&gt;
&lt;br /&gt;
==== carte mère nue ====&lt;br /&gt;
[[Fichier:PCB_carte_mère_nu.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== carte mère avec ATmega 328p ====&lt;br /&gt;
&lt;br /&gt;
== Programmation ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Bilan de puissance ==&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Liens ==&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6769</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6769"/>
		<updated>2024-11-19T13:48:08Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Programmation ordonnanceur */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PINOUT ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage du shield ===&lt;br /&gt;
&lt;br /&gt;
==== shield nu ====&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== shield fini ====&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Test du shield ===&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|679x679px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage carte mère ===&lt;br /&gt;
&lt;br /&gt;
==== carte mère nue ====&lt;br /&gt;
[[Fichier:PCB_carte_mère_nu.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Programmation ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Bilan de puissance ==&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Liens ==&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6768</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6768"/>
		<updated>2024-11-19T13:46:47Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Brasage carte mère */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PINOUT ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage du shield ===&lt;br /&gt;
&lt;br /&gt;
==== shield nu ====&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== shield fini ====&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Test du shield ===&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|679x679px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage carte mère ===&lt;br /&gt;
&lt;br /&gt;
==== carte mère nue ====&lt;br /&gt;
[[Fichier:PCB carte mère nu.jpg|gauche|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Bilan de puissance ==&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Liens ==&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6767</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6767"/>
		<updated>2024-11-19T13:39:42Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Description */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PINOUT ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage du shield ===&lt;br /&gt;
&lt;br /&gt;
==== shield nu ====&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== shield fini ====&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Test du shield ===&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|679x679px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage carte mère ===&lt;br /&gt;
&lt;br /&gt;
==== carte mère nue ====&lt;br /&gt;
[[Fichier:PCB carte mère nu.jpg|gauche|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Bilan de puissance ==&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Liens ==&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6766</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6766"/>
		<updated>2024-11-19T13:34:42Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Réalisation carte mère */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== PINOUT ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Brasage du shield==&lt;br /&gt;
&lt;br /&gt;
=== shield nu===&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
===shield fini===&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==Test du shield==&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|679x679px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Brasage carte mère ===&lt;br /&gt;
[[Fichier:PCB carte mère nu.jpg|gauche|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Bilan de puissance ==&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Liens ==&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:PCB_carte_m%C3%A8re_nu.jpg&amp;diff=6765</id>
		<title>Fichier:PCB carte mère nu.jpg</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:PCB_carte_m%C3%A8re_nu.jpg&amp;diff=6765"/>
		<updated>2024-11-19T13:33:52Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;.&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6692</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6692"/>
		<updated>2024-11-18T09:47:33Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Bilan de puissance */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== PINOUT ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Brasage du shield==&lt;br /&gt;
&lt;br /&gt;
=== shield nu===&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
===shield fini===&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==Test du shield==&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|679x679px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Programmation ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Bilan de puissance ==&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Liens ==&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6691</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6691"/>
		<updated>2024-11-18T09:44:31Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Schématique et routage */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== PINOUT ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Brasage du shield==&lt;br /&gt;
&lt;br /&gt;
=== shield nu===&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
===shield fini===&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==Test du shield==&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|679x679px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Programmation ordonnanceur=&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
= Bilan de puissance =&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Liens=&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6690</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6690"/>
		<updated>2024-11-18T09:43:59Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Schématique et routage */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== PINOUT ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Brasage du shield==&lt;br /&gt;
&lt;br /&gt;
=== shield nu===&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
===shield fini===&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==Test du shield==&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|709x709px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Programmation ordonnanceur=&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
= Bilan de puissance =&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Liens=&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6688</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6688"/>
		<updated>2024-11-18T09:43:11Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Schématique et routage */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== PINOUT ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Brasage du shield==&lt;br /&gt;
&lt;br /&gt;
=== shield nu===&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
===shield fini===&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==Test du shield==&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|749x749px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Programmation ordonnanceur=&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
= Bilan de puissance =&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Liens=&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6687</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6687"/>
		<updated>2024-11-18T09:42:07Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Schématique et routage */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== PINOUT ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Brasage du shield==&lt;br /&gt;
&lt;br /&gt;
=== shield nu===&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
===shield fini===&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==Test du shield==&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|759x759px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Programmation ordonnanceur=&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
= Bilan de puissance =&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Liens=&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6685</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6685"/>
		<updated>2024-11-18T09:40:39Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Réalisation d'un shield arduino */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et Routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:PicoShield SCH Detrez Cart.pdf|sans_cadre|639x639px]]&lt;br /&gt;
![[Fichier:Routage shield CART DETREZ.png|sans_cadre|638x638px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== PINOUT ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Brasage du shield==&lt;br /&gt;
&lt;br /&gt;
=== shield nu===&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
===shield fini===&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==Test du shield==&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|759x759px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Programmation ordonnanceur=&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
= Bilan de puissance =&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Liens=&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:PicoShield_SCH_Detrez_Cart.pdf&amp;diff=6683</id>
		<title>Fichier:PicoShield SCH Detrez Cart.pdf</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:PicoShield_SCH_Detrez_Cart.pdf&amp;diff=6683"/>
		<updated>2024-11-18T09:37:42Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;.&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6678</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6678"/>
		<updated>2024-11-18T09:21:26Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Description */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
== Description ==&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
== Réalisation d'un shield arduino ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique ===&lt;br /&gt;
[[Fichier:Schematique shield CART DETREZ.pdf|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== Routage ===&lt;br /&gt;
[[Fichier:Routage shield CART DETREZ.png|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== PINOUT ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Brasage du shield==&lt;br /&gt;
&lt;br /&gt;
=== shield nu===&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
===shield fini===&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==Test du shield==&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Réalisation carte mère ==&lt;br /&gt;
&lt;br /&gt;
=== Schématique et routage ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
![[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|759x759px]]&lt;br /&gt;
![[Fichier:Schématique Carte mere .png|centré|sans_cadre|575x575px]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Programmation ordonnanceur=&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
= Bilan de puissance =&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; |Bilan de puissance (Vcc = 5V)&lt;br /&gt;
|-&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
!&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; |Bilan de puissance général du groupe&lt;br /&gt;
|-&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|5,55W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Liens=&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6649</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6649"/>
		<updated>2024-11-13T11:05:10Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Description */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Fichier:Titre page pico carte mère cart detrez.png|centré|sans_cadre|972x972px]]&lt;br /&gt;
&lt;br /&gt;
= Description =&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
=== Choix technologique ===&lt;br /&gt;
Pour alimenter les cartes filles, nous avons fait le choix de rendre disponible à la fois le 3v3 et le 5v. Pour ce faire nous allons utiliser des connecteurs HE -0 10 pins et non 8 pins dont voici les références :&lt;br /&gt;
&lt;br /&gt;
- &lt;br /&gt;
&lt;br /&gt;
= Réalisation d'un shield arduino =&lt;br /&gt;
&lt;br /&gt;
== Schématique ==&lt;br /&gt;
[[Fichier:Schematique shield CART DETREZ.pdf|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Routage ==&lt;br /&gt;
[[Fichier:Routage shield CART DETREZ.png|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== PINOUT==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Brasage du shield==&lt;br /&gt;
&lt;br /&gt;
=== shield nu===&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
===shield fini===&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==Test du shield==&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
= Réalisation carte mère =&lt;br /&gt;
&lt;br /&gt;
== Schématique ==&lt;br /&gt;
[[Fichier:Schématique Carte mere CART DETREZ.pdf|centré|sans_cadre|759x759px]]&lt;br /&gt;
&lt;br /&gt;
== Routage ==&lt;br /&gt;
&lt;br /&gt;
=Programmation ordonnanceur=&lt;br /&gt;
&lt;br /&gt;
=== Initialisation de la pile ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.&lt;br /&gt;
&lt;br /&gt;
=== Interruption de l'ordonnanceur ===&lt;br /&gt;
L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.&lt;br /&gt;
&lt;br /&gt;
Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
    /* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[currentTask].stackPointer = SP;&lt;br /&gt;
    /* Appel à l'ordonnanceur */&lt;br /&gt;
    scheduler();&lt;br /&gt;
    /* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
    SP = task[currentTask].stackPointer;&lt;br /&gt;
    RESTORE_REGISTERS();&lt;br /&gt;
    asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La routine d'interruption est générée par le '''Timer1''' avec comme paramètre ISR_NAKED qui permet de ne pas avoir le prologue et l'épilogue automatique du compilateur ce qui nous est très utile pour gérer manuellement ces interruptions afin d'éxecuter nos tâches.&lt;br /&gt;
&lt;br /&gt;
La macro '''''SAVE_REGISTERS()''''' nous permet de sauvegarder les 32 registres sur la pile. Cela permet de s’assurer qu’au retour de l'interruption, la tâche interrompue pourra reprendre son exécution là où elle s’était arrêtée, sans perdre son contexte.&lt;br /&gt;
&lt;br /&gt;
'''''task[currentTask].stackPointer = SP''''' permet de sauvegarder le pointeur de pile de la tâche associée.&lt;br /&gt;
&lt;br /&gt;
'''''scheduler()''''' est expliqué [[SE4Binome2024-3#Code de l'ordonnanceur|ici]].&lt;br /&gt;
&lt;br /&gt;
'''''SP = task[currentTask].stackPointer''''' permet de replacer le pointeur de pile à celui de la nouvelle tâche engendrée par le scheduler.&lt;br /&gt;
&lt;br /&gt;
La macro '''''RESTORE_REGISTERS()''''' remets la nouvelle fonction sur les 32 registres avec des Pop().&lt;br /&gt;
&lt;br /&gt;
'''''asm volatile ( &amp;quot;reti&amp;quot; )''''' : étant en ISR_NAKED, il faut dire manuellement la fin de l'interruption avec cette commande assembleur '''RETurn from Interrupt'''.&lt;br /&gt;
&lt;br /&gt;
=== Structure d'une tâche ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
enum States{&lt;br /&gt;
    AWAKE,&lt;br /&gt;
    IDLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
enum IDLE_TYPE{&lt;br /&gt;
    IDLE_TYPE_DELAY,&lt;br /&gt;
    IDLE_TYPE_STABLE&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
typedef union {&lt;br /&gt;
  int sleeping_time;&lt;br /&gt;
} Time;&lt;br /&gt;
&lt;br /&gt;
typedef struct {&lt;br /&gt;
  enum IDLE_TYPE type;&lt;br /&gt;
  Time time;&lt;br /&gt;
} Etat ;&lt;br /&gt;
&lt;br /&gt;
typedef struct{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    enum States state; // état de la fonction (Awake ou Idle)&lt;br /&gt;
    Etat etat;&lt;br /&gt;
}process;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les tâches sont définies par leurs pointeurs de piles, leurs adresses, un état qui est soit IDLE ou AWAKE et enfin un dernier état qui lui gère permet d'avoir différent type d'IDLE.&lt;br /&gt;
&lt;br /&gt;
L'utilisation d'[[wikipedia:Union_type#C/C++|unions]] n'est pas forcément justifiée ici mais permet de limiter la place que va prendre la structure dans l'optique de futures implémentations.&lt;br /&gt;
&lt;br /&gt;
=== Code de l'ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler(){&lt;br /&gt;
&lt;br /&gt;
// décrémentation de l'attente de toutes les tâches en IDLE&lt;br /&gt;
for(int i=0;i&amp;lt;NB_TASKS;i++){&lt;br /&gt;
    if(task[i].state==IDLE &amp;amp;&amp;amp; (task[i].etat.type==IDLE_TYPE_DELAY)){&lt;br /&gt;
        task[i].etat.time.sleeping_time -= PERIODE;&lt;br /&gt;
        if(task[i].etat.time.sleeping_time &amp;lt;= 0){&lt;br /&gt;
            task[i].etat.time.sleeping_time = 0;&lt;br /&gt;
            task[i].state = AWAKE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
do{&lt;br /&gt;
  currentTask ++;&lt;br /&gt;
  if(currentTask &amp;gt;= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
  }while(task[currentTask].state == IDLE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'ordonnanceur est en mode [https://fr.wikipedia.org/wiki/Round-robin_(informatique) Round Robin] (tourniquet) ce qui veut dire qu'il n'y a pas de priorité de tâche, elles sont toutes appelées une à une dans l'ordre avant de boucler et ainsi de suite...&lt;br /&gt;
&lt;br /&gt;
L'un des ajouts a été de mettre un mode IDLE à nos tâches qui indique la veille de ces dernières. Si une tâche est en IDLE, elle ne sera pas appelée lors de la sélection des tâches et son temps de sommeil sera décrémenté. Cela permet de créer des attentes passives donc d'éviter d'attendre inutilement des tâches qui ne font qu'attendre. On bon exemple pour comprendre serait avec un [[SE4Binome2024-3#Exemple de tâches|clignotement de LED]]. Au lieu de mettre un _delay_ms(1000) qui éxecutera une attente à chaque fois que cette tâche est appelée, on la passe pendant 1000 ms ce qui permet d'éxécuter d'autres tâches entre temps.&lt;br /&gt;
&lt;br /&gt;
=== Fonction wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait(int time_ms){&lt;br /&gt;
    task[currentTask].state = IDLE;&lt;br /&gt;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;&lt;br /&gt;
    task[currentTask].etat.time.sleeping_time = time_ms;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;La fonction permet d'endormir un processus pendant un temps donné en ms. &lt;br /&gt;
&lt;br /&gt;
Elle passe la tâche en IDLE, remet le '''Timer1''' à zéro pour éviter de garder un décalage de temps car le changement est surement fait en plein milieu d'une tâche.&lt;br /&gt;
&lt;br /&gt;
Et ensuite elle appelle l'interruption pour qu'une nouvelle tâche soit en cours.&lt;br /&gt;
&lt;br /&gt;
=== Exemple de tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(1000);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        wait(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                              // Activer le périphérique&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_SS);                            // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                           // Désactiver le périphérique&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;SPI_SS);                             // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI&lt;br /&gt;
    SPDR = envoi;                                        // Octet a envoyer&lt;br /&gt;
    while(!(SPSR &amp;amp; (1&amp;lt;&amp;lt;SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)&lt;br /&gt;
    return SPDR;                                         // Octet reçu&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void seven_seg(){&lt;br /&gt;
    while(1){&lt;br /&gt;
    spi_activer();&lt;br /&gt;
    spi_echange(0x01);&lt;br /&gt;
    spi_desactiver();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
= Bilan de puissance =&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Bilan de puissance (Vcc = 5V)&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Bilan de puissance général du groupe&lt;br /&gt;
!CARTE&lt;br /&gt;
!PUISSANCE (maximale)&lt;br /&gt;
|-&lt;br /&gt;
|Mère&lt;br /&gt;
|0,63W&lt;br /&gt;
|-&lt;br /&gt;
|Clavier&lt;br /&gt;
|1,735W&lt;br /&gt;
|-&lt;br /&gt;
|Réseau&lt;br /&gt;
|0,15W&lt;br /&gt;
|-&lt;br /&gt;
|Ecran&lt;br /&gt;
|0,17W&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''2,685W'''&lt;br /&gt;
|}&lt;br /&gt;
Afin d'être sûr de l'alimentation de toutes les cartes, nous utilisons une alimentation +5V d'une Raspberry PI branchée sur secteur.&lt;br /&gt;
&lt;br /&gt;
=Liens=&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Titre_page_pico_carte_m%C3%A8re_cart_detrez.png&amp;diff=6646</id>
		<title>Fichier:Titre page pico carte mère cart detrez.png</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Titre_page_pico_carte_m%C3%A8re_cart_detrez.png&amp;diff=6646"/>
		<updated>2024-11-13T11:04:41Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;.&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6439</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6439"/>
		<updated>2024-10-23T10:17:45Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Description =&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
=== Choix technologique ===&lt;br /&gt;
Pour alimenter les cartes filles, nous avons fait le choix de rendre disponible à la fois le 3v3 et le 5v. Pour ce faire nous allons utiliser des connecteurs HE -0 10 pins et non 8 pins dont voici les références :&lt;br /&gt;
&lt;br /&gt;
- &lt;br /&gt;
&lt;br /&gt;
= Réalisation d'un shield arduino =&lt;br /&gt;
&lt;br /&gt;
== Schématique ==&lt;br /&gt;
[[Fichier:Schematique shield CART DETREZ.pdf|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Routage ==&lt;br /&gt;
[[Fichier:Routage shield CART DETREZ.png|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== PINOUT==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Brasage du shield==&lt;br /&gt;
&lt;br /&gt;
=== shield nu===&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
===shield fini===&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==Test du shield==&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
= Réalisation carte mère =&lt;br /&gt;
&lt;br /&gt;
== Schématique ==&lt;br /&gt;
&lt;br /&gt;
== Routage ==&lt;br /&gt;
&lt;br /&gt;
=Programmation ordonnanceur=&lt;br /&gt;
&lt;br /&gt;
=== Code ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;Fonctions.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#define RESTORE_REGISTERS() \&lt;br /&gt;
asm volatile ( \&lt;br /&gt;
    &amp;quot;pop r31 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r30 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r29 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r28 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r27 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r26 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r25 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r24 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r23 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r22 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r21 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r20 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r19 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r18 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r17 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r16 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r15 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r14 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r13 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r12 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r11 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r10 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r9 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r8 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r7 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r6 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r5 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r4 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r3 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r2 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r1 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;out __SREG__, r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r0 \n\t&amp;quot; \&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
#define SAVE_REGISTERS() \&lt;br /&gt;
asm volatile ( \&lt;br /&gt;
    &amp;quot;push r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;in r0, __SREG__ \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r1 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r2 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r3 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r4 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r5 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r6 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r7 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r8 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r9 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r10 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r11 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r12 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r13 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r14 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r15 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r16 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r17 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r18 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r19 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r20 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r21 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r22 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r23 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r24 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r25 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r26 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r27 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r28 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r29 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r30 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r31 \n\t&amp;quot; \&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
int currentTask = 0;&lt;br /&gt;
//uint16_t SP = 0x700;&lt;br /&gt;
&lt;br /&gt;
// FONCTIONS&lt;br /&gt;
&lt;br /&gt;
// Déclaration des différentes tâches&lt;br /&gt;
process task[NB_TASKS] = {&lt;br /&gt;
    {0x700,Serial_Led,0},&lt;br /&gt;
    {0x600, LED1_blink,0},&lt;br /&gt;
    {0x500, Serial_Message,0}&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void init_minuteur(int diviseur,long periode){&lt;br /&gt;
TCCR1A=0;               // Le mode choisi n'utilise pas ce registre&lt;br /&gt;
TCCR1B=(1&amp;lt;&amp;lt;CTC1);       // Réinitialisation du minuteur sur expiration&lt;br /&gt;
switch(diviseur){&lt;br /&gt;
  case    8: TCCR1B |= (1&amp;lt;&amp;lt;CS11); break;&lt;br /&gt;
  case   64: TCCR1B |= (1&amp;lt;&amp;lt;CS11 | 11&amp;lt;&amp;lt;CS10); break;&lt;br /&gt;
  case  256: TCCR1B |= (1&amp;lt;&amp;lt;CS12); break;&lt;br /&gt;
  case 1024: TCCR1B |= (1&amp;lt;&amp;lt;CS12 | 1&amp;lt;&amp;lt;CS10); break;&lt;br /&gt;
  }&lt;br /&gt;
// Un cycle prend 1/F_CPU secondes.&lt;br /&gt;
// Un pas de compteur prend diviseur/F_CPU secondes.&lt;br /&gt;
// Pour une periode en millisecondes, il faut (periode/1000)/(diviseur/F_CPU) pas&lt;br /&gt;
// soit (periode*F_CPU)/(1000*diviseur)&lt;br /&gt;
OCR1A=F_CPU/1000*periode/diviseur;  // Calcul du pas&lt;br /&gt;
TCNT1=0;                // Compteur initialisé&lt;br /&gt;
TIMSK1=(1&amp;lt;&amp;lt;OCIE1A);     // Comparaison du compteur avec OCR1A&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void scheduler(){&lt;br /&gt;
    currentTask ++;&lt;br /&gt;
    if(currentTask == NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Déclaration d'un tableau de processus&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
/* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
SAVE_REGISTERS();&lt;br /&gt;
task[currentTask].stackPointer = SP;&lt;br /&gt;
/* Appel à l'ordonnanceur */&lt;br /&gt;
scheduler();&lt;br /&gt;
/* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
SP = task[currentTask].stackPointer;&lt;br /&gt;
RESTORE_REGISTERS();&lt;br /&gt;
asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(void){&lt;br /&gt;
cli();&lt;br /&gt;
LED_init();&lt;br /&gt;
USART_Init(MYUBRR);&lt;br /&gt;
init_minuteur(256,PERIODE);&lt;br /&gt;
for(int i=1;i&amp;lt;NB_TASKS;i++) init_pile(i);&lt;br /&gt;
SP = task[0].stackPointer;&lt;br /&gt;
sei();&lt;br /&gt;
task[0].addressFunction();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code des tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef FONCTIONS_H&lt;br /&gt;
#define FONCTIONS_H&lt;br /&gt;
&lt;br /&gt;
// Inclusions de bibliothèques nécessaires&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define CTC1            WGM12           // Meilleur nom pour le bit&lt;br /&gt;
&lt;br /&gt;
#define PERIODE         20&lt;br /&gt;
#define FOSC 16000000 // Clock Speed&lt;br /&gt;
#define BAUD 9600&lt;br /&gt;
#define MYUBRR FOSC/16/BAUD-1&lt;br /&gt;
&lt;br /&gt;
#define LED1 PC0&lt;br /&gt;
#define LED2 PC3&lt;br /&gt;
#define LED3 PD1&lt;br /&gt;
#define LED4 PD4&lt;br /&gt;
#define LED5 PD7&lt;br /&gt;
&lt;br /&gt;
#define NB_TASKS 3&lt;br /&gt;
&lt;br /&gt;
typedef struct process{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    int state; // état de la fonction (prêt, en cours, terminé)&lt;br /&gt;
}process;&lt;br /&gt;
&lt;br /&gt;
void LED_init(void);&lt;br /&gt;
void USART_Init(unsigned int ubrr);&lt;br /&gt;
void LED1_blink(void);&lt;br /&gt;
void LED2_blink(void);&lt;br /&gt;
void LED3_blink(void);&lt;br /&gt;
void LED4_blink(void);&lt;br /&gt;
void LED5_blink(void);&lt;br /&gt;
void USART_Transmit(unsigned char data);&lt;br /&gt;
unsigned char USART_Receive(void);&lt;br /&gt;
void Serial_Led();&lt;br /&gt;
void Serial_Message();&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;Fonctions.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(150);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        _delay_ms(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED3_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED3);&lt;br /&gt;
        _delay_ms(250);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED4_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED4);&lt;br /&gt;
        _delay_ms(350);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED5_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
        _delay_ms(50);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void Serial_Led(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        if(USART_Receive() == 'a') LED2_blink();&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
= Bilan de puissance =&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Bilan de puissance (VCC = 3.3V)&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|74LVC125&lt;br /&gt;
|40 uA&lt;br /&gt;
|0.2mW&lt;br /&gt;
|-&lt;br /&gt;
|Carte SD&lt;br /&gt;
|100 mA&lt;br /&gt;
|330 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''100,04 mA'''&lt;br /&gt;
|'''330.2 mW'''&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Bilan de puissance (Vcc = 5V)&lt;br /&gt;
!Composant&lt;br /&gt;
!Courant&lt;br /&gt;
!Puissance&lt;br /&gt;
|-&lt;br /&gt;
|AtMega328p&lt;br /&gt;
|14mA&lt;br /&gt;
|70mW&lt;br /&gt;
|-&lt;br /&gt;
|ATMega8U2&lt;br /&gt;
|21mA&lt;br /&gt;
|105mW&lt;br /&gt;
|-&lt;br /&gt;
|5xLED&lt;br /&gt;
|5*5mA&lt;br /&gt;
|5*25 mW&lt;br /&gt;
|-&lt;br /&gt;
|'''TOTAL'''&lt;br /&gt;
|'''60mA'''&lt;br /&gt;
|'''300 mW'''&lt;br /&gt;
|}&lt;br /&gt;
=Liens=&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6438</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6438"/>
		<updated>2024-10-23T10:17:24Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Description =&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
=== Choix technologique ===&lt;br /&gt;
Pour alimenter les cartes filles, nous avons fait le choix de rendre disponible à la fois le 3v3 et le 5v. Pour ce faire nous allons utiliser des connecteurs HE -0 10 pins et non 8 pins dont voici les références :&lt;br /&gt;
&lt;br /&gt;
- &lt;br /&gt;
&lt;br /&gt;
= Réalisation d'un shield arduino =&lt;br /&gt;
&lt;br /&gt;
== Schématique ==&lt;br /&gt;
[[Fichier:Schematique shield CART DETREZ.pdf|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Routage ==&lt;br /&gt;
[[Fichier:Routage shield CART DETREZ.png|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== PINOUT==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Brasage du shield==&lt;br /&gt;
&lt;br /&gt;
=== shield nu===&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
===shield fini===&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==Test du shield==&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
= Réalisation carte mère =&lt;br /&gt;
&lt;br /&gt;
== Schématique ==&lt;br /&gt;
&lt;br /&gt;
== Routage ==&lt;br /&gt;
&lt;br /&gt;
=Programmation ordonnanceur=&lt;br /&gt;
&lt;br /&gt;
=== Code ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;Fonctions.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#define RESTORE_REGISTERS() \&lt;br /&gt;
asm volatile ( \&lt;br /&gt;
    &amp;quot;pop r31 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r30 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r29 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r28 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r27 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r26 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r25 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r24 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r23 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r22 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r21 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r20 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r19 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r18 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r17 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r16 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r15 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r14 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r13 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r12 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r11 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r10 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r9 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r8 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r7 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r6 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r5 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r4 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r3 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r2 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r1 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;out __SREG__, r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r0 \n\t&amp;quot; \&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
#define SAVE_REGISTERS() \&lt;br /&gt;
asm volatile ( \&lt;br /&gt;
    &amp;quot;push r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;in r0, __SREG__ \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r1 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r2 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r3 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r4 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r5 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r6 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r7 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r8 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r9 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r10 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r11 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r12 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r13 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r14 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r15 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r16 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r17 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r18 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r19 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r20 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r21 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r22 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r23 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r24 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r25 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r26 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r27 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r28 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r29 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r30 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r31 \n\t&amp;quot; \&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
int currentTask = 0;&lt;br /&gt;
//uint16_t SP = 0x700;&lt;br /&gt;
&lt;br /&gt;
// FONCTIONS&lt;br /&gt;
&lt;br /&gt;
// Déclaration des différentes tâches&lt;br /&gt;
process task[NB_TASKS] = {&lt;br /&gt;
    {0x700,Serial_Led,0},&lt;br /&gt;
    {0x600, LED1_blink,0},&lt;br /&gt;
    {0x500, Serial_Message,0}&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void init_minuteur(int diviseur,long periode){&lt;br /&gt;
TCCR1A=0;               // Le mode choisi n'utilise pas ce registre&lt;br /&gt;
TCCR1B=(1&amp;lt;&amp;lt;CTC1);       // Réinitialisation du minuteur sur expiration&lt;br /&gt;
switch(diviseur){&lt;br /&gt;
  case    8: TCCR1B |= (1&amp;lt;&amp;lt;CS11); break;&lt;br /&gt;
  case   64: TCCR1B |= (1&amp;lt;&amp;lt;CS11 | 11&amp;lt;&amp;lt;CS10); break;&lt;br /&gt;
  case  256: TCCR1B |= (1&amp;lt;&amp;lt;CS12); break;&lt;br /&gt;
  case 1024: TCCR1B |= (1&amp;lt;&amp;lt;CS12 | 1&amp;lt;&amp;lt;CS10); break;&lt;br /&gt;
  }&lt;br /&gt;
// Un cycle prend 1/F_CPU secondes.&lt;br /&gt;
// Un pas de compteur prend diviseur/F_CPU secondes.&lt;br /&gt;
// Pour une periode en millisecondes, il faut (periode/1000)/(diviseur/F_CPU) pas&lt;br /&gt;
// soit (periode*F_CPU)/(1000*diviseur)&lt;br /&gt;
OCR1A=F_CPU/1000*periode/diviseur;  // Calcul du pas&lt;br /&gt;
TCNT1=0;                // Compteur initialisé&lt;br /&gt;
TIMSK1=(1&amp;lt;&amp;lt;OCIE1A);     // Comparaison du compteur avec OCR1A&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void scheduler(){&lt;br /&gt;
    currentTask ++;&lt;br /&gt;
    if(currentTask == NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Déclaration d'un tableau de processus&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
/* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
SAVE_REGISTERS();&lt;br /&gt;
task[currentTask].stackPointer = SP;&lt;br /&gt;
/* Appel à l'ordonnanceur */&lt;br /&gt;
scheduler();&lt;br /&gt;
/* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
SP = task[currentTask].stackPointer;&lt;br /&gt;
RESTORE_REGISTERS();&lt;br /&gt;
asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(void){&lt;br /&gt;
cli();&lt;br /&gt;
LED_init();&lt;br /&gt;
USART_Init(MYUBRR);&lt;br /&gt;
init_minuteur(256,PERIODE);&lt;br /&gt;
for(int i=1;i&amp;lt;NB_TASKS;i++) init_pile(i);&lt;br /&gt;
SP = task[0].stackPointer;&lt;br /&gt;
sei();&lt;br /&gt;
task[0].addressFunction();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code des tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef FONCTIONS_H&lt;br /&gt;
#define FONCTIONS_H&lt;br /&gt;
&lt;br /&gt;
// Inclusions de bibliothèques nécessaires&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define CTC1            WGM12           // Meilleur nom pour le bit&lt;br /&gt;
&lt;br /&gt;
#define PERIODE         20&lt;br /&gt;
#define FOSC 16000000 // Clock Speed&lt;br /&gt;
#define BAUD 9600&lt;br /&gt;
#define MYUBRR FOSC/16/BAUD-1&lt;br /&gt;
&lt;br /&gt;
#define LED1 PC0&lt;br /&gt;
#define LED2 PC3&lt;br /&gt;
#define LED3 PD1&lt;br /&gt;
#define LED4 PD4&lt;br /&gt;
#define LED5 PD7&lt;br /&gt;
&lt;br /&gt;
#define NB_TASKS 3&lt;br /&gt;
&lt;br /&gt;
typedef struct process{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    int state; // état de la fonction (prêt, en cours, terminé)&lt;br /&gt;
}process;&lt;br /&gt;
&lt;br /&gt;
void LED_init(void);&lt;br /&gt;
void USART_Init(unsigned int ubrr);&lt;br /&gt;
void LED1_blink(void);&lt;br /&gt;
void LED2_blink(void);&lt;br /&gt;
void LED3_blink(void);&lt;br /&gt;
void LED4_blink(void);&lt;br /&gt;
void LED5_blink(void);&lt;br /&gt;
void USART_Transmit(unsigned char data);&lt;br /&gt;
unsigned char USART_Receive(void);&lt;br /&gt;
void Serial_Led();&lt;br /&gt;
void Serial_Message();&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;Fonctions.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(150);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        _delay_ms(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED3_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED3);&lt;br /&gt;
        _delay_ms(250);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED4_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED4);&lt;br /&gt;
        _delay_ms(350);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED5_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
        _delay_ms(50);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void Serial_Led(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        if(USART_Receive() == 'a') LED2_blink();&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
= Bilan de puissance =&lt;br /&gt;
&lt;br /&gt;
=Liens=&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6301</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6301"/>
		<updated>2024-10-15T13:50:47Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Réalisation d'un shield arduino */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Description =&lt;br /&gt;
L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.&lt;br /&gt;
&lt;br /&gt;
Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB. &lt;br /&gt;
&lt;br /&gt;
=== Choix technologique ===&lt;br /&gt;
Pour alimenter les cartes filles, nous avons fait le choix de rendre disponible à la fois le 3v3 et le 5v. Pour ce faire nous allons utiliser des connecteurs HE -0 10 pins et non 8 pins dont voici les références :&lt;br /&gt;
&lt;br /&gt;
- &lt;br /&gt;
&lt;br /&gt;
= Réalisation d'un shield arduino =&lt;br /&gt;
&lt;br /&gt;
== Schématique ==&lt;br /&gt;
[[Fichier:Schematique shield CART DETREZ.pdf|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Routage ==&lt;br /&gt;
[[Fichier:Routage shield CART DETREZ.png|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== PINOUT==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Brasage du shield==&lt;br /&gt;
&lt;br /&gt;
=== shield nu===&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
===shield fini===&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==Test du shield==&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
= Réalisation carte mère =&lt;br /&gt;
&lt;br /&gt;
== Schématique ==&lt;br /&gt;
&lt;br /&gt;
== Routage ==&lt;br /&gt;
&lt;br /&gt;
=Programmation ordonnanceur=&lt;br /&gt;
&lt;br /&gt;
=== Code ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;Fonctions.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#define RESTORE_REGISTERS() \&lt;br /&gt;
asm volatile ( \&lt;br /&gt;
    &amp;quot;pop r31 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r30 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r29 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r28 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r27 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r26 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r25 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r24 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r23 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r22 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r21 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r20 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r19 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r18 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r17 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r16 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r15 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r14 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r13 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r12 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r11 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r10 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r9 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r8 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r7 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r6 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r5 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r4 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r3 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r2 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r1 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;out __SREG__, r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r0 \n\t&amp;quot; \&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
#define SAVE_REGISTERS() \&lt;br /&gt;
asm volatile ( \&lt;br /&gt;
    &amp;quot;push r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;in r0, __SREG__ \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r1 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r2 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r3 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r4 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r5 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r6 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r7 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r8 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r9 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r10 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r11 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r12 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r13 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r14 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r15 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r16 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r17 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r18 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r19 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r20 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r21 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r22 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r23 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r24 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r25 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r26 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r27 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r28 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r29 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r30 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r31 \n\t&amp;quot; \&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
int currentTask = 0;&lt;br /&gt;
//uint16_t SP = 0x700;&lt;br /&gt;
&lt;br /&gt;
// FONCTIONS&lt;br /&gt;
&lt;br /&gt;
// Déclaration des différentes tâches&lt;br /&gt;
process task[NB_TASKS] = {&lt;br /&gt;
    {0x700,Serial_Led,0},&lt;br /&gt;
    {0x600, LED1_blink,0},&lt;br /&gt;
    {0x500, Serial_Message,0}&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void init_minuteur(int diviseur,long periode){&lt;br /&gt;
TCCR1A=0;               // Le mode choisi n'utilise pas ce registre&lt;br /&gt;
TCCR1B=(1&amp;lt;&amp;lt;CTC1);       // Réinitialisation du minuteur sur expiration&lt;br /&gt;
switch(diviseur){&lt;br /&gt;
  case    8: TCCR1B |= (1&amp;lt;&amp;lt;CS11); break;&lt;br /&gt;
  case   64: TCCR1B |= (1&amp;lt;&amp;lt;CS11 | 11&amp;lt;&amp;lt;CS10); break;&lt;br /&gt;
  case  256: TCCR1B |= (1&amp;lt;&amp;lt;CS12); break;&lt;br /&gt;
  case 1024: TCCR1B |= (1&amp;lt;&amp;lt;CS12 | 1&amp;lt;&amp;lt;CS10); break;&lt;br /&gt;
  }&lt;br /&gt;
// Un cycle prend 1/F_CPU secondes.&lt;br /&gt;
// Un pas de compteur prend diviseur/F_CPU secondes.&lt;br /&gt;
// Pour une periode en millisecondes, il faut (periode/1000)/(diviseur/F_CPU) pas&lt;br /&gt;
// soit (periode*F_CPU)/(1000*diviseur)&lt;br /&gt;
OCR1A=F_CPU/1000*periode/diviseur;  // Calcul du pas&lt;br /&gt;
TCNT1=0;                // Compteur initialisé&lt;br /&gt;
TIMSK1=(1&amp;lt;&amp;lt;OCIE1A);     // Comparaison du compteur avec OCR1A&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void scheduler(){&lt;br /&gt;
    currentTask ++;&lt;br /&gt;
    if(currentTask == NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Déclaration d'un tableau de processus&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
/* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
SAVE_REGISTERS();&lt;br /&gt;
task[currentTask].stackPointer = SP;&lt;br /&gt;
/* Appel à l'ordonnanceur */&lt;br /&gt;
scheduler();&lt;br /&gt;
/* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
SP = task[currentTask].stackPointer;&lt;br /&gt;
RESTORE_REGISTERS();&lt;br /&gt;
asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(void){&lt;br /&gt;
cli();&lt;br /&gt;
LED_init();&lt;br /&gt;
USART_Init(MYUBRR);&lt;br /&gt;
init_minuteur(256,PERIODE);&lt;br /&gt;
for(int i=1;i&amp;lt;NB_TASKS;i++) init_pile(i);&lt;br /&gt;
SP = task[0].stackPointer;&lt;br /&gt;
sei();&lt;br /&gt;
task[0].addressFunction();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code des tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef FONCTIONS_H&lt;br /&gt;
#define FONCTIONS_H&lt;br /&gt;
&lt;br /&gt;
// Inclusions de bibliothèques nécessaires&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define CTC1            WGM12           // Meilleur nom pour le bit&lt;br /&gt;
&lt;br /&gt;
#define PERIODE         20&lt;br /&gt;
#define FOSC 16000000 // Clock Speed&lt;br /&gt;
#define BAUD 9600&lt;br /&gt;
#define MYUBRR FOSC/16/BAUD-1&lt;br /&gt;
&lt;br /&gt;
#define LED1 PC0&lt;br /&gt;
#define LED2 PC3&lt;br /&gt;
#define LED3 PD1&lt;br /&gt;
#define LED4 PD4&lt;br /&gt;
#define LED5 PD7&lt;br /&gt;
&lt;br /&gt;
#define NB_TASKS 3&lt;br /&gt;
&lt;br /&gt;
typedef struct process{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    int state; // état de la fonction (prêt, en cours, terminé)&lt;br /&gt;
}process;&lt;br /&gt;
&lt;br /&gt;
void LED_init(void);&lt;br /&gt;
void USART_Init(unsigned int ubrr);&lt;br /&gt;
void LED1_blink(void);&lt;br /&gt;
void LED2_blink(void);&lt;br /&gt;
void LED3_blink(void);&lt;br /&gt;
void LED4_blink(void);&lt;br /&gt;
void LED5_blink(void);&lt;br /&gt;
void USART_Transmit(unsigned char data);&lt;br /&gt;
unsigned char USART_Receive(void);&lt;br /&gt;
void Serial_Led();&lt;br /&gt;
void Serial_Message();&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;Fonctions.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(150);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        _delay_ms(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED3_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED3);&lt;br /&gt;
        _delay_ms(250);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED4_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED4);&lt;br /&gt;
        _delay_ms(350);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED5_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
        _delay_ms(50);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void Serial_Led(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        if(USART_Receive() == 'a') LED2_blink();&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=Liens=&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6258</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6258"/>
		<updated>2024-10-15T12:21:53Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Réalisation d'un shield arduino =&lt;br /&gt;
&lt;br /&gt;
== Schématique ==&lt;br /&gt;
[[Fichier:Schematique shield CART DETREZ.pdf|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Routage ==&lt;br /&gt;
[[Fichier:Routage shield CART DETREZ.png|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== PINOUT==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Brasage du shield==&lt;br /&gt;
&lt;br /&gt;
=== shield nu===&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
===shield fini===&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==Test du shield==&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
= Réalisation carte mère =&lt;br /&gt;
&lt;br /&gt;
== Schématique ==&lt;br /&gt;
&lt;br /&gt;
== Routage ==&lt;br /&gt;
&lt;br /&gt;
=Programmation ordonnanceur=&lt;br /&gt;
&lt;br /&gt;
=== Code ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;Fonctions.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#define RESTORE_REGISTERS() \&lt;br /&gt;
asm volatile ( \&lt;br /&gt;
    &amp;quot;pop r31 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r30 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r29 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r28 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r27 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r26 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r25 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r24 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r23 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r22 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r21 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r20 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r19 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r18 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r17 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r16 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r15 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r14 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r13 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r12 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r11 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r10 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r9 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r8 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r7 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r6 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r5 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r4 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r3 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r2 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r1 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;out __SREG__, r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r0 \n\t&amp;quot; \&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
#define SAVE_REGISTERS() \&lt;br /&gt;
asm volatile ( \&lt;br /&gt;
    &amp;quot;push r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;in r0, __SREG__ \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r1 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r2 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r3 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r4 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r5 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r6 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r7 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r8 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r9 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r10 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r11 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r12 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r13 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r14 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r15 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r16 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r17 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r18 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r19 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r20 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r21 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r22 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r23 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r24 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r25 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r26 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r27 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r28 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r29 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r30 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r31 \n\t&amp;quot; \&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
int currentTask = 0;&lt;br /&gt;
//uint16_t SP = 0x700;&lt;br /&gt;
&lt;br /&gt;
// FONCTIONS&lt;br /&gt;
&lt;br /&gt;
// Déclaration des différentes tâches&lt;br /&gt;
process task[NB_TASKS] = {&lt;br /&gt;
    {0x700,Serial_Led,0},&lt;br /&gt;
    {0x600, LED1_blink,0},&lt;br /&gt;
    {0x500, Serial_Message,0}&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void init_minuteur(int diviseur,long periode){&lt;br /&gt;
TCCR1A=0;               // Le mode choisi n'utilise pas ce registre&lt;br /&gt;
TCCR1B=(1&amp;lt;&amp;lt;CTC1);       // Réinitialisation du minuteur sur expiration&lt;br /&gt;
switch(diviseur){&lt;br /&gt;
  case    8: TCCR1B |= (1&amp;lt;&amp;lt;CS11); break;&lt;br /&gt;
  case   64: TCCR1B |= (1&amp;lt;&amp;lt;CS11 | 11&amp;lt;&amp;lt;CS10); break;&lt;br /&gt;
  case  256: TCCR1B |= (1&amp;lt;&amp;lt;CS12); break;&lt;br /&gt;
  case 1024: TCCR1B |= (1&amp;lt;&amp;lt;CS12 | 1&amp;lt;&amp;lt;CS10); break;&lt;br /&gt;
  }&lt;br /&gt;
// Un cycle prend 1/F_CPU secondes.&lt;br /&gt;
// Un pas de compteur prend diviseur/F_CPU secondes.&lt;br /&gt;
// Pour une periode en millisecondes, il faut (periode/1000)/(diviseur/F_CPU) pas&lt;br /&gt;
// soit (periode*F_CPU)/(1000*diviseur)&lt;br /&gt;
OCR1A=F_CPU/1000*periode/diviseur;  // Calcul du pas&lt;br /&gt;
TCNT1=0;                // Compteur initialisé&lt;br /&gt;
TIMSK1=(1&amp;lt;&amp;lt;OCIE1A);     // Comparaison du compteur avec OCR1A&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void scheduler(){&lt;br /&gt;
    currentTask ++;&lt;br /&gt;
    if(currentTask == NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Déclaration d'un tableau de processus&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
/* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
SAVE_REGISTERS();&lt;br /&gt;
task[currentTask].stackPointer = SP;&lt;br /&gt;
/* Appel à l'ordonnanceur */&lt;br /&gt;
scheduler();&lt;br /&gt;
/* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
SP = task[currentTask].stackPointer;&lt;br /&gt;
RESTORE_REGISTERS();&lt;br /&gt;
asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(void){&lt;br /&gt;
cli();&lt;br /&gt;
LED_init();&lt;br /&gt;
USART_Init(MYUBRR);&lt;br /&gt;
init_minuteur(256,PERIODE);&lt;br /&gt;
for(int i=1;i&amp;lt;NB_TASKS;i++) init_pile(i);&lt;br /&gt;
SP = task[0].stackPointer;&lt;br /&gt;
sei();&lt;br /&gt;
task[0].addressFunction();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code des tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef FONCTIONS_H&lt;br /&gt;
#define FONCTIONS_H&lt;br /&gt;
&lt;br /&gt;
// Inclusions de bibliothèques nécessaires&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define CTC1            WGM12           // Meilleur nom pour le bit&lt;br /&gt;
&lt;br /&gt;
#define PERIODE         20&lt;br /&gt;
#define FOSC 16000000 // Clock Speed&lt;br /&gt;
#define BAUD 9600&lt;br /&gt;
#define MYUBRR FOSC/16/BAUD-1&lt;br /&gt;
&lt;br /&gt;
#define LED1 PC0&lt;br /&gt;
#define LED2 PC3&lt;br /&gt;
#define LED3 PD1&lt;br /&gt;
#define LED4 PD4&lt;br /&gt;
#define LED5 PD7&lt;br /&gt;
&lt;br /&gt;
#define NB_TASKS 3&lt;br /&gt;
&lt;br /&gt;
typedef struct process{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    int state; // état de la fonction (prêt, en cours, terminé)&lt;br /&gt;
}process;&lt;br /&gt;
&lt;br /&gt;
void LED_init(void);&lt;br /&gt;
void USART_Init(unsigned int ubrr);&lt;br /&gt;
void LED1_blink(void);&lt;br /&gt;
void LED2_blink(void);&lt;br /&gt;
void LED3_blink(void);&lt;br /&gt;
void LED4_blink(void);&lt;br /&gt;
void LED5_blink(void);&lt;br /&gt;
void USART_Transmit(unsigned char data);&lt;br /&gt;
unsigned char USART_Receive(void);&lt;br /&gt;
void Serial_Led();&lt;br /&gt;
void Serial_Message();&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;Fonctions.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(150);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        _delay_ms(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED3_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED3);&lt;br /&gt;
        _delay_ms(250);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED4_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED4);&lt;br /&gt;
        _delay_ms(350);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED5_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
        _delay_ms(50);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void Serial_Led(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        if(USART_Receive() == 'a') LED2_blink();&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=Liens=&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6253</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6253"/>
		<updated>2024-10-15T12:13:28Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Clignotement de 5 Leds asynchrones */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Réalisation d'un shield arduino =&lt;br /&gt;
&lt;br /&gt;
== Schématique ==&lt;br /&gt;
[[Fichier:Schematique shield CART DETREZ.pdf|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Routage ==&lt;br /&gt;
[[Fichier:Routage shield CART DETREZ.png|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== PINOUT==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Brasage du shield==&lt;br /&gt;
&lt;br /&gt;
=== shield nu===&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
===shield fini===&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==Test du shield==&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=Programmation ordonnanceur=&lt;br /&gt;
&lt;br /&gt;
=== Code ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;Fonctions.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#define RESTORE_REGISTERS() \&lt;br /&gt;
asm volatile ( \&lt;br /&gt;
    &amp;quot;pop r31 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r30 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r29 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r28 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r27 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r26 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r25 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r24 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r23 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r22 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r21 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r20 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r19 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r18 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r17 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r16 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r15 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r14 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r13 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r12 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r11 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r10 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r9 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r8 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r7 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r6 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r5 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r4 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r3 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r2 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r1 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;out __SREG__, r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r0 \n\t&amp;quot; \&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
#define SAVE_REGISTERS() \&lt;br /&gt;
asm volatile ( \&lt;br /&gt;
    &amp;quot;push r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;in r0, __SREG__ \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r1 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r2 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r3 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r4 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r5 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r6 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r7 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r8 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r9 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r10 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r11 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r12 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r13 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r14 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r15 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r16 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r17 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r18 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r19 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r20 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r21 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r22 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r23 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r24 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r25 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r26 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r27 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r28 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r29 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r30 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r31 \n\t&amp;quot; \&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
int currentTask = 0;&lt;br /&gt;
//uint16_t SP = 0x700;&lt;br /&gt;
&lt;br /&gt;
// FONCTIONS&lt;br /&gt;
&lt;br /&gt;
// Déclaration des différentes tâches&lt;br /&gt;
process task[NB_TASKS] = {&lt;br /&gt;
    {0x700,Serial_Led,0},&lt;br /&gt;
    {0x600, LED1_blink,0},&lt;br /&gt;
    {0x500, Serial_Message,0}&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void init_minuteur(int diviseur,long periode){&lt;br /&gt;
TCCR1A=0;               // Le mode choisi n'utilise pas ce registre&lt;br /&gt;
TCCR1B=(1&amp;lt;&amp;lt;CTC1);       // Réinitialisation du minuteur sur expiration&lt;br /&gt;
switch(diviseur){&lt;br /&gt;
  case    8: TCCR1B |= (1&amp;lt;&amp;lt;CS11); break;&lt;br /&gt;
  case   64: TCCR1B |= (1&amp;lt;&amp;lt;CS11 | 11&amp;lt;&amp;lt;CS10); break;&lt;br /&gt;
  case  256: TCCR1B |= (1&amp;lt;&amp;lt;CS12); break;&lt;br /&gt;
  case 1024: TCCR1B |= (1&amp;lt;&amp;lt;CS12 | 1&amp;lt;&amp;lt;CS10); break;&lt;br /&gt;
  }&lt;br /&gt;
// Un cycle prend 1/F_CPU secondes.&lt;br /&gt;
// Un pas de compteur prend diviseur/F_CPU secondes.&lt;br /&gt;
// Pour une periode en millisecondes, il faut (periode/1000)/(diviseur/F_CPU) pas&lt;br /&gt;
// soit (periode*F_CPU)/(1000*diviseur)&lt;br /&gt;
OCR1A=F_CPU/1000*periode/diviseur;  // Calcul du pas&lt;br /&gt;
TCNT1=0;                // Compteur initialisé&lt;br /&gt;
TIMSK1=(1&amp;lt;&amp;lt;OCIE1A);     // Comparaison du compteur avec OCR1A&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void scheduler(){&lt;br /&gt;
    currentTask ++;&lt;br /&gt;
    if(currentTask == NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Déclaration d'un tableau de processus&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
/* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
SAVE_REGISTERS();&lt;br /&gt;
task[currentTask].stackPointer = SP;&lt;br /&gt;
/* Appel à l'ordonnanceur */&lt;br /&gt;
scheduler();&lt;br /&gt;
/* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
SP = task[currentTask].stackPointer;&lt;br /&gt;
RESTORE_REGISTERS();&lt;br /&gt;
asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(void){&lt;br /&gt;
cli();&lt;br /&gt;
LED_init();&lt;br /&gt;
USART_Init(MYUBRR);&lt;br /&gt;
init_minuteur(256,PERIODE);&lt;br /&gt;
for(int i=1;i&amp;lt;NB_TASKS;i++) init_pile(i);&lt;br /&gt;
SP = task[0].stackPointer;&lt;br /&gt;
sei();&lt;br /&gt;
task[0].addressFunction();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code des tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef FONCTIONS_H&lt;br /&gt;
#define FONCTIONS_H&lt;br /&gt;
&lt;br /&gt;
// Inclusions de bibliothèques nécessaires&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define CTC1            WGM12           // Meilleur nom pour le bit&lt;br /&gt;
&lt;br /&gt;
#define PERIODE         20&lt;br /&gt;
#define FOSC 16000000 // Clock Speed&lt;br /&gt;
#define BAUD 9600&lt;br /&gt;
#define MYUBRR FOSC/16/BAUD-1&lt;br /&gt;
&lt;br /&gt;
#define LED1 PC0&lt;br /&gt;
#define LED2 PC3&lt;br /&gt;
#define LED3 PD1&lt;br /&gt;
#define LED4 PD4&lt;br /&gt;
#define LED5 PD7&lt;br /&gt;
&lt;br /&gt;
#define NB_TASKS 3&lt;br /&gt;
&lt;br /&gt;
typedef struct process{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    int state; // état de la fonction (prêt, en cours, terminé)&lt;br /&gt;
}process;&lt;br /&gt;
&lt;br /&gt;
void LED_init(void);&lt;br /&gt;
void USART_Init(unsigned int ubrr);&lt;br /&gt;
void LED1_blink(void);&lt;br /&gt;
void LED2_blink(void);&lt;br /&gt;
void LED3_blink(void);&lt;br /&gt;
void LED4_blink(void);&lt;br /&gt;
void LED5_blink(void);&lt;br /&gt;
void USART_Transmit(unsigned char data);&lt;br /&gt;
unsigned char USART_Receive(void);&lt;br /&gt;
void Serial_Led();&lt;br /&gt;
void Serial_Message();&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;Fonctions.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(150);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        _delay_ms(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED3_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED3);&lt;br /&gt;
        _delay_ms(250);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED4_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED4);&lt;br /&gt;
        _delay_ms(350);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED5_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
        _delay_ms(50);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void Serial_Led(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        if(USART_Receive() == 'a') LED2_blink();&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==== Affichage clavier avec minicom ====&lt;br /&gt;
[[Fichier:Affichage clavier minicom.mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=Liens=&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Affichage_clavier_minicom.mp4&amp;diff=6252</id>
		<title>Fichier:Affichage clavier minicom.mp4</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Affichage_clavier_minicom.mp4&amp;diff=6252"/>
		<updated>2024-10-15T12:13:01Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;.&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6248</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6248"/>
		<updated>2024-10-15T12:03:43Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Code ordonnanceur */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Réalisation d'un shield arduino =&lt;br /&gt;
&lt;br /&gt;
== Schématique ==&lt;br /&gt;
[[Fichier:Schematique shield CART DETREZ.pdf|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Routage ==&lt;br /&gt;
[[Fichier:Routage shield CART DETREZ.png|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== PINOUT==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Brasage du shield==&lt;br /&gt;
&lt;br /&gt;
=== shield nu===&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
===shield fini===&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==Test du shield==&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=Programmation ordonnanceur=&lt;br /&gt;
&lt;br /&gt;
=== Code ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;Fonctions.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#define RESTORE_REGISTERS() \&lt;br /&gt;
asm volatile ( \&lt;br /&gt;
    &amp;quot;pop r31 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r30 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r29 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r28 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r27 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r26 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r25 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r24 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r23 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r22 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r21 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r20 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r19 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r18 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r17 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r16 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r15 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r14 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r13 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r12 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r11 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r10 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r9 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r8 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r7 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r6 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r5 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r4 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r3 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r2 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r1 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;out __SREG__, r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r0 \n\t&amp;quot; \&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
#define SAVE_REGISTERS() \&lt;br /&gt;
asm volatile ( \&lt;br /&gt;
    &amp;quot;push r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;in r0, __SREG__ \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r1 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r2 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r3 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r4 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r5 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r6 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r7 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r8 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r9 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r10 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r11 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r12 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r13 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r14 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r15 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r16 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r17 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r18 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r19 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r20 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r21 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r22 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r23 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r24 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r25 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r26 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r27 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r28 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r29 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r30 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r31 \n\t&amp;quot; \&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
int currentTask = 0;&lt;br /&gt;
//uint16_t SP = 0x700;&lt;br /&gt;
&lt;br /&gt;
// FONCTIONS&lt;br /&gt;
&lt;br /&gt;
// Déclaration des différentes tâches&lt;br /&gt;
process task[NB_TASKS] = {&lt;br /&gt;
    {0x700,Serial_Led,0},&lt;br /&gt;
    {0x600, LED1_blink,0},&lt;br /&gt;
    {0x500, Serial_Message,0}&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void init_minuteur(int diviseur,long periode){&lt;br /&gt;
TCCR1A=0;               // Le mode choisi n'utilise pas ce registre&lt;br /&gt;
TCCR1B=(1&amp;lt;&amp;lt;CTC1);       // Réinitialisation du minuteur sur expiration&lt;br /&gt;
switch(diviseur){&lt;br /&gt;
  case    8: TCCR1B |= (1&amp;lt;&amp;lt;CS11); break;&lt;br /&gt;
  case   64: TCCR1B |= (1&amp;lt;&amp;lt;CS11 | 11&amp;lt;&amp;lt;CS10); break;&lt;br /&gt;
  case  256: TCCR1B |= (1&amp;lt;&amp;lt;CS12); break;&lt;br /&gt;
  case 1024: TCCR1B |= (1&amp;lt;&amp;lt;CS12 | 1&amp;lt;&amp;lt;CS10); break;&lt;br /&gt;
  }&lt;br /&gt;
// Un cycle prend 1/F_CPU secondes.&lt;br /&gt;
// Un pas de compteur prend diviseur/F_CPU secondes.&lt;br /&gt;
// Pour une periode en millisecondes, il faut (periode/1000)/(diviseur/F_CPU) pas&lt;br /&gt;
// soit (periode*F_CPU)/(1000*diviseur)&lt;br /&gt;
OCR1A=F_CPU/1000*periode/diviseur;  // Calcul du pas&lt;br /&gt;
TCNT1=0;                // Compteur initialisé&lt;br /&gt;
TIMSK1=(1&amp;lt;&amp;lt;OCIE1A);     // Comparaison du compteur avec OCR1A&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void scheduler(){&lt;br /&gt;
    currentTask ++;&lt;br /&gt;
    if(currentTask == NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Déclaration d'un tableau de processus&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
/* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
SAVE_REGISTERS();&lt;br /&gt;
task[currentTask].stackPointer = SP;&lt;br /&gt;
/* Appel à l'ordonnanceur */&lt;br /&gt;
scheduler();&lt;br /&gt;
/* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
SP = task[currentTask].stackPointer;&lt;br /&gt;
RESTORE_REGISTERS();&lt;br /&gt;
asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(void){&lt;br /&gt;
cli();&lt;br /&gt;
LED_init();&lt;br /&gt;
USART_Init(MYUBRR);&lt;br /&gt;
init_minuteur(256,PERIODE);&lt;br /&gt;
for(int i=1;i&amp;lt;NB_TASKS;i++) init_pile(i);&lt;br /&gt;
SP = task[0].stackPointer;&lt;br /&gt;
sei();&lt;br /&gt;
task[0].addressFunction();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code des tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef FONCTIONS_H&lt;br /&gt;
#define FONCTIONS_H&lt;br /&gt;
&lt;br /&gt;
// Inclusions de bibliothèques nécessaires&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define CTC1            WGM12           // Meilleur nom pour le bit&lt;br /&gt;
&lt;br /&gt;
#define PERIODE         20&lt;br /&gt;
#define FOSC 16000000 // Clock Speed&lt;br /&gt;
#define BAUD 9600&lt;br /&gt;
#define MYUBRR FOSC/16/BAUD-1&lt;br /&gt;
&lt;br /&gt;
#define LED1 PC0&lt;br /&gt;
#define LED2 PC3&lt;br /&gt;
#define LED3 PD1&lt;br /&gt;
#define LED4 PD4&lt;br /&gt;
#define LED5 PD7&lt;br /&gt;
&lt;br /&gt;
#define NB_TASKS 3&lt;br /&gt;
&lt;br /&gt;
typedef struct process{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    int state; // état de la fonction (prêt, en cours, terminé)&lt;br /&gt;
}process;&lt;br /&gt;
&lt;br /&gt;
void LED_init(void);&lt;br /&gt;
void USART_Init(unsigned int ubrr);&lt;br /&gt;
void LED1_blink(void);&lt;br /&gt;
void LED2_blink(void);&lt;br /&gt;
void LED3_blink(void);&lt;br /&gt;
void LED4_blink(void);&lt;br /&gt;
void LED5_blink(void);&lt;br /&gt;
void USART_Transmit(unsigned char data);&lt;br /&gt;
unsigned char USART_Receive(void);&lt;br /&gt;
void Serial_Led();&lt;br /&gt;
void Serial_Message();&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;Fonctions.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Init(unsigned int ubrr)&lt;br /&gt;
{&lt;br /&gt;
/*Set baud rate */&lt;br /&gt;
UBRR0H = (unsigned char)(ubrr&amp;gt;&amp;gt;8);&lt;br /&gt;
UBRR0L = (unsigned char)ubrr;&lt;br /&gt;
/*Enable receiver and transmitter */&lt;br /&gt;
UCSR0B = (1&amp;lt;&amp;lt;RXEN0)|(1&amp;lt;&amp;lt;TXEN0);&lt;br /&gt;
/* Set frame format: 8data, 2stop bit */&lt;br /&gt;
UCSR0C = (1&amp;lt;&amp;lt;USBS0)|(3&amp;lt;&amp;lt;UCSZ00);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(150);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        _delay_ms(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED3_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED3);&lt;br /&gt;
        _delay_ms(250);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED4_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED4);&lt;br /&gt;
        _delay_ms(350);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED5_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
        _delay_ms(50);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void Serial_Led(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        if(USART_Receive() == 'a') LED2_blink();&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void Serial_Message(){&lt;br /&gt;
    unsigned char data;&lt;br /&gt;
    while(1){&lt;br /&gt;
         data = USART_Receive();&lt;br /&gt;
        USART_Transmit(data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void USART_Transmit(unsigned char data)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for empty transmit buffer */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;UDRE0)))&lt;br /&gt;
;&lt;br /&gt;
/* Put data into buffer, sends the data */&lt;br /&gt;
UDR0 = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
unsigned char USART_Receive(void)&lt;br /&gt;
{&lt;br /&gt;
/* Wait for data to be received */&lt;br /&gt;
while (!(UCSR0A &amp;amp; (1&amp;lt;&amp;lt;RXC0)))&lt;br /&gt;
;&lt;br /&gt;
/* Get and return received data from buffer */&lt;br /&gt;
return UDR0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=Liens=&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6231</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6231"/>
		<updated>2024-10-14T09:01:38Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Code ordonnanceur */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Réalisation d'un shield arduino =&lt;br /&gt;
&lt;br /&gt;
== Schématique ==&lt;br /&gt;
[[Fichier:Schematique shield CART DETREZ.pdf|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Routage ==&lt;br /&gt;
[[Fichier:Routage shield CART DETREZ.png|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== PINOUT==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Brasage du shield==&lt;br /&gt;
&lt;br /&gt;
=== shield nu===&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
===shield fini===&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==Test du shield==&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=Programmation ordonnanceur=&lt;br /&gt;
&lt;br /&gt;
=== Code ordonnanceur ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;Fonctions.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
#define RESTORE_REGISTERS() \&lt;br /&gt;
asm volatile ( \&lt;br /&gt;
    &amp;quot;pop r31 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r30 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r29 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r28 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r27 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r26 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r25 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r24 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r23 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r22 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r21 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r20 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r19 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r18 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r17 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r16 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r15 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r14 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r13 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r12 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r11 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r10 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r9 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r8 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r7 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r6 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r5 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r4 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r3 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r2 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r1 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;out __SREG__, r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;pop r0 \n\t&amp;quot; \&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
#define SAVE_REGISTERS() \&lt;br /&gt;
asm volatile ( \&lt;br /&gt;
    &amp;quot;push r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;in r0, __SREG__ \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r0 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r1 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r2 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r3 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r4 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r5 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r6 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r7 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r8 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r9 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r10 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r11 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r12 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r13 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r14 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r15 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r16 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r17 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r18 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r19 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r20 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r21 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r22 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r23 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r24 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r25 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r26 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r27 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r28 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r29 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r30 \n\t&amp;quot; \&lt;br /&gt;
    &amp;quot;push r31 \n\t&amp;quot; \&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
int currentTask = 0;&lt;br /&gt;
//uint16_t SP = 0x700;&lt;br /&gt;
&lt;br /&gt;
// FONCTIONS&lt;br /&gt;
&lt;br /&gt;
// Déclaration des différentes tâches&lt;br /&gt;
process task[NB_TASKS] = {&lt;br /&gt;
    {0x700,LED1_blink,0},&lt;br /&gt;
    {0x600, LED2_blink,0},&lt;br /&gt;
    {0x500, LED3_blink,0},&lt;br /&gt;
    {0x400, LED4_blink,0},&lt;br /&gt;
    {0x300, LED5_blink,0}&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
void init_pile(int N){&lt;br /&gt;
    uint16_t tempSP = SP;&lt;br /&gt;
    SP = task[N].stackPointer;&lt;br /&gt;
    uint16_t adresse=(uint16_t)task[N].addressFunction;&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; (adresse &amp;amp; 0x00ff) );&lt;br /&gt;
    asm volatile(&amp;quot;push %0&amp;quot; : : &amp;quot;r&amp;quot; ((adresse &amp;amp; 0xff00)&amp;gt;&amp;gt;8) );&lt;br /&gt;
    SAVE_REGISTERS();&lt;br /&gt;
    task[N].stackPointer = SP;&lt;br /&gt;
    SP = tempSP;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void init_minuteur(int diviseur,long periode){&lt;br /&gt;
TCCR1A=0;               // Le mode choisi n'utilise pas ce registre&lt;br /&gt;
TCCR1B=(1&amp;lt;&amp;lt;CTC1);       // Réinitialisation du minuteur sur expiration&lt;br /&gt;
switch(diviseur){&lt;br /&gt;
  case    8: TCCR1B |= (1&amp;lt;&amp;lt;CS11); break;&lt;br /&gt;
  case   64: TCCR1B |= (1&amp;lt;&amp;lt;CS11 | 11&amp;lt;&amp;lt;CS10); break;&lt;br /&gt;
  case  256: TCCR1B |= (1&amp;lt;&amp;lt;CS12); break;&lt;br /&gt;
  case 1024: TCCR1B |= (1&amp;lt;&amp;lt;CS12 | 1&amp;lt;&amp;lt;CS10); break;&lt;br /&gt;
  }&lt;br /&gt;
// Un cycle prend 1/F_CPU secondes.&lt;br /&gt;
// Un pas de compteur prend diviseur/F_CPU secondes.&lt;br /&gt;
// Pour une periode en millisecondes, il faut (periode/1000)/(diviseur/F_CPU) pas&lt;br /&gt;
// soit (periode*F_CPU)/(1000*diviseur)&lt;br /&gt;
OCR1A=F_CPU/1000*periode/diviseur;  // Calcul du pas&lt;br /&gt;
TCNT1=0;                // Compteur initialisé&lt;br /&gt;
TIMSK1=(1&amp;lt;&amp;lt;OCIE1A);     // Comparaison du compteur avec OCR1A&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void scheduler(){&lt;br /&gt;
    currentTask ++;&lt;br /&gt;
    if(currentTask == NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Déclaration d'un tableau de processus&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption&lt;br /&gt;
/* Sauvegarde du contexte de la tâche interrompue */&lt;br /&gt;
SAVE_REGISTERS();&lt;br /&gt;
task[currentTask].stackPointer = SP;&lt;br /&gt;
/* Appel à l'ordonnanceur */&lt;br /&gt;
scheduler();&lt;br /&gt;
/* Récupération du contexte de la tâche ré-activée */&lt;br /&gt;
SP = task[currentTask].stackPointer;&lt;br /&gt;
RESTORE_REGISTERS();&lt;br /&gt;
asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(void){&lt;br /&gt;
cli();&lt;br /&gt;
LED_init();&lt;br /&gt;
init_minuteur(256,PERIODE);&lt;br /&gt;
for(int i=1;i&amp;lt;NB_TASKS;i++) init_pile(i);&lt;br /&gt;
SP = task[0].stackPointer;&lt;br /&gt;
sei();&lt;br /&gt;
task[0].addressFunction();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code des tâches ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#ifndef FONCTIONS_H&lt;br /&gt;
#define FONCTIONS_H&lt;br /&gt;
&lt;br /&gt;
// Inclusions de bibliothèques nécessaires&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/interrupt.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;util/delay.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define CTC1            WGM12           // Meilleur nom pour le bit&lt;br /&gt;
&lt;br /&gt;
#define PERIODE         20&lt;br /&gt;
&lt;br /&gt;
#define LED1 PC0&lt;br /&gt;
#define LED2 PC3&lt;br /&gt;
#define LED3 PD1&lt;br /&gt;
#define LED4 PD4&lt;br /&gt;
#define LED5 PD7&lt;br /&gt;
&lt;br /&gt;
#define NB_TASKS 5&lt;br /&gt;
&lt;br /&gt;
typedef struct process{&lt;br /&gt;
    uint16_t stackPointer; // stack pointer, défini le début du process&lt;br /&gt;
    void (*addressFunction)(void); // adresse de l'instruction en cours&lt;br /&gt;
    int state; // état de la fonction (prêt, en cours, terminé)&lt;br /&gt;
}process;&lt;br /&gt;
&lt;br /&gt;
void LED_init(void);&lt;br /&gt;
void LED1_blink(void);&lt;br /&gt;
void LED2_blink(void);&lt;br /&gt;
void LED3_blink(void);&lt;br /&gt;
void LED4_blink(void);&lt;br /&gt;
void LED5_blink(void);&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;1&amp;quot; start=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;Fonctions.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
void LED_init(){&lt;br /&gt;
    DDRC |= (1&amp;lt;&amp;lt;LED1) | (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;LED3) | (1&amp;lt;&amp;lt;LED4) | (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
    PORTC |= (1&amp;lt;&amp;lt;LED1)|(1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;LED3)|(1&amp;lt;&amp;lt;LED4)|(1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED1_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED1);&lt;br /&gt;
        _delay_ms(150);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED2_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTC ^= (1&amp;lt;&amp;lt;LED2);&lt;br /&gt;
        _delay_ms(100);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED3_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED3);&lt;br /&gt;
        _delay_ms(250);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED4_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED4);&lt;br /&gt;
        _delay_ms(350);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void LED5_blink(){&lt;br /&gt;
    while(1){&lt;br /&gt;
        PORTD ^= (1&amp;lt;&amp;lt;LED5);&lt;br /&gt;
        _delay_ms(50);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exemple d'utilisation ===&lt;br /&gt;
&lt;br /&gt;
==== Clignotement de 5 Leds asynchrones ====&lt;br /&gt;
[[Fichier:Clignotement 5 leds .mp4|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=Liens=&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Clignotement_5_leds_.mp4&amp;diff=6230</id>
		<title>Fichier:Clignotement 5 leds .mp4</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Clignotement_5_leds_.mp4&amp;diff=6230"/>
		<updated>2024-10-14T09:01:21Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;.&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6184</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6184"/>
		<updated>2024-10-07T08:34:53Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* Réalisation d'un shield arduino */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Réalisation d'un shield arduino =&lt;br /&gt;
&lt;br /&gt;
== Schématique ==&lt;br /&gt;
[[Fichier:Schematique shield CART DETREZ.pdf|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Routage ==&lt;br /&gt;
[[Fichier:Routage shield CART DETREZ.png|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== PINOUT==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|LED1&lt;br /&gt;
|PC0&lt;br /&gt;
|-&lt;br /&gt;
|LED2&lt;br /&gt;
|PC3&lt;br /&gt;
|-&lt;br /&gt;
|LED3&lt;br /&gt;
|PD1&lt;br /&gt;
|-&lt;br /&gt;
|LED4&lt;br /&gt;
|PD4&lt;br /&gt;
|-&lt;br /&gt;
|LED5 &lt;br /&gt;
|PD7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Brasage du shield==&lt;br /&gt;
&lt;br /&gt;
=== shield nu===&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
===shield fini===&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
==Test du shield==&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=Code ordonnanceur=&lt;br /&gt;
&lt;br /&gt;
=Liens=&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6183</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6183"/>
		<updated>2024-10-07T08:25:24Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : /* shield nu: */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Réalisation d'un shield arduino =&lt;br /&gt;
&lt;br /&gt;
== Schématique ==&lt;br /&gt;
[[Fichier:Schematique shield CART DETREZ.pdf|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Routage ==&lt;br /&gt;
[[Fichier:Routage shield CART DETREZ.png|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Brasage du shield ==&lt;br /&gt;
&lt;br /&gt;
=== shield nu ===&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== shield fini ===&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Test du shield ==&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
= Code ordonnanceur =&lt;br /&gt;
&lt;br /&gt;
= Liens =&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6182</id>
		<title>SE4Binome2024-3</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2024-3&amp;diff=6182"/>
		<updated>2024-10-07T08:24:58Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Réalisation d'un shield arduino =&lt;br /&gt;
&lt;br /&gt;
== Schématique ==&lt;br /&gt;
[[Fichier:Schematique shield CART DETREZ.pdf|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Routage ==&lt;br /&gt;
[[Fichier:Routage shield CART DETREZ.png|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Brasage du shield ==&lt;br /&gt;
&lt;br /&gt;
=== shield nu: ===&lt;br /&gt;
[[Fichier:Shield nu CART DETREZ 2.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
=== shield fini: ===&lt;br /&gt;
[[Fichier:Shield fini CART DETREZ.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
== Test du shield ==&lt;br /&gt;
[[Fichier:Affichage 7 segments DETREZ CART.jpg|sans_cadre]]&lt;br /&gt;
&lt;br /&gt;
= Code ordonnanceur =&lt;br /&gt;
&lt;br /&gt;
= Liens =&lt;br /&gt;
Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Affichage_7_segments_DETREZ_CART.jpg&amp;diff=6181</id>
		<title>Fichier:Affichage 7 segments DETREZ CART.jpg</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Affichage_7_segments_DETREZ_CART.jpg&amp;diff=6181"/>
		<updated>2024-10-07T08:24:13Z</updated>

		<summary type="html">&lt;p&gt;Vdetrez : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;.&lt;/div&gt;</summary>
		<author><name>Vdetrez</name></author>
	</entry>
</feed>