<?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=Apalifer</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=Apalifer"/>
	<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php/Sp%C3%A9cial:Contributions/Apalifer"/>
	<updated>2026-05-14T04:01:13Z</updated>
	<subtitle>Contributions</subtitle>
	<generator>MediaWiki 1.39.1</generator>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3189</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3189"/>
		<updated>2024-01-18T21:09:37Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Partie 2 - Programmation de la carte électronique : */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
Le détail de notre code et de notre routage est disponible sur notre git : https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matérielle de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivants :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des câbles de liaison HE10 carte-mère/carte-fille avec des câbles plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des leds et résistances, et des ports HE10 mâles&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de leds. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500 ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000 ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les leds allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux leds clignotent à son rythme et les deux processus de gestion des leds fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au ''delay_ms'', n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' que nous avons implémentée permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction ''scheduler'', commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de leds afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // configuration sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // configuration entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérées par la mise à l'état haut ou bas de la ligne Slave Select.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                                  // Activer la communication&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;4);                                    // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                               // Désactiver la communication&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principale qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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 d'envoi&lt;br /&gt;
    return SPDR;                                         // octet reçu&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et de gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utilisé l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données séries asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Comme il est possible de constater sur la vidéo ci-dessus, nous arrivons à lire depuis l'Arduino sur le port série. Ainsi, dès qu'un caractère est tapé au clavier, il est affiché sur la matrice de LEDs.&lt;br /&gt;
&lt;br /&gt;
=== Démonstration d'écriture sur le port série : ===&lt;br /&gt;
[[Fichier:Ecriture serie.mp4|centré|vignette|Ecriture serie]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nous sommes également capables d'écrire depuis le port série, les données sont envoyées depuis l'Arduino et afficher sur l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;.(ici nous renvoyons simplement le caractere tapé au clavier)&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numérique =&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était de concevoir et de créer un circuit imprimé (PCB) pour une carte écran LCD, englobant chaque étape du processus, depuis l'élaboration du schéma initial jusqu'à la programmation de l'affichage sur l'écran. &lt;br /&gt;
&lt;br /&gt;
Ainsi, cette partie abordera plus en détail les points suivants :&lt;br /&gt;
&lt;br /&gt;
# Réalisation du PCB&lt;br /&gt;
#* Schematic&lt;br /&gt;
#* Routage&lt;br /&gt;
#* Soudure&lt;br /&gt;
# Programmation de la carte électronique&lt;br /&gt;
#* Code, explications et tests&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
=== Partie 1 - réalisation du PCB : ===&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontrôleur Atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte-mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p certains ports n'étaient pas connectés aux endroits attendus. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustrer correctement le fonctionnement de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|vignette|Schematic final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi dû adapter notre routage pour qu'il corresponde avec notre carte une fois le circuit corrigé.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|vignette|Routage final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et tests : ====&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'Arduino en tant qu'ISP, mais nous obtenions une erreur. &lt;br /&gt;
Également, après un test en programmant directement la carte avec un programme simple en C et un ficher Makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer, mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précédemment, les connexions de l'AVR ISP étaient finalement en cause. Nous avons donc réussi à corriger le problème directement en câblant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|Partie supérieure[[Fichier:Partie supérieure carte écran .png|alt=Partie supérieure carte écran |centré|vignette|400x400px|Partie supérieure carte écran ]]&lt;br /&gt;
|Partie inférieure[[Fichier:Partie inféreure carte écran .png|alt=Partie inférieure carte écran |centré|vignette|400x400px|Partie inférieure carte écran ]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs). L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêchait d'afficher sur l'écran. Erreur certainement causée au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
Ainsi, nous avons pu tester le programme &amp;quot;blink&amp;quot; fourni dans l'Arduino IDE et constater que notre carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Partie 2 - Programmation de la carte électronique : ===&lt;br /&gt;
&lt;br /&gt;
Pour le code de la partie écran, nous avons les fichiers LCD.c et LCD.h qui implémentent les fonctions permettant l'interaction avec l'écran. La fonction ''LCD_WriteText'' permet d'écrire une chaîne de caractères sur l'écran de manière à ce que le passage à la nouvelle ligne se fasse automatiquement.&lt;br /&gt;
&lt;br /&gt;
Le fichier main.c inclut le programme qui utilise LCD.h afin de faire fonctionner l’écran.&lt;br /&gt;
&lt;br /&gt;
Ainsi, nous pouvons programmer l'Atmega328p de notre carte électronique.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
    LCD_EraseScreen(2, 16);// Efface l'écran avant d'écrire dessus&lt;br /&gt;
&lt;br /&gt;
	LCD_WriteText(&amp;quot;test 123!&amp;quot;, 2, 16, &amp;amp;row, &amp;amp;col, second_line_buff, &amp;amp;second_line_index);// écriture initiale&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	_delay_ms(100);&lt;br /&gt;
	LCD_WriteText(&amp;quot; Hello! :)&amp;quot;, 2, 16, &amp;amp;row, &amp;amp;col, second_line_buff, &amp;amp;second_line_index);// écriture consecutive&lt;br /&gt;
	_delay_ms(50);&lt;br /&gt;
&lt;br /&gt;
	LCD_WriteText(&amp;quot;Now writing to much text so that the screen scrools down&amp;quot;, 2, 16, &amp;amp;row, &amp;amp;col, second_line_buff, &amp;amp;second_line_index);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Cela fait fonctionner l'écran comme sur la vidéo suivante:&lt;br /&gt;
[[Fichier:Ecran fonctionne.mp4|vignette|L'écran fonctionne|centré]]&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme la communication série ou encore les composants systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons eu certaines difficultés lors de la conception de notre PCB. Ces difficultés nous ont coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'Arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'Arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3188</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3188"/>
		<updated>2024-01-18T21:08:48Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Corrections */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
Le détail de notre code et de notre routage est disponible sur notre git : https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matérielle de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivants :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des câbles de liaison HE10 carte-mère/carte-fille avec des câbles plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des leds et résistances, et des ports HE10 mâles&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de leds. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500 ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000 ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les leds allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux leds clignotent à son rythme et les deux processus de gestion des leds fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au ''delay_ms'', n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' que nous avons implémentée permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction ''scheduler'', commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de leds afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // configuration sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // configuration entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérées par la mise à l'état haut ou bas de la ligne Slave Select.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                                  // Activer la communication&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;4);                                    // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                               // Désactiver la communication&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principale qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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 d'envoi&lt;br /&gt;
    return SPDR;                                         // octet reçu&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et de gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utilisé l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données séries asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Comme il est possible de constater sur la vidéo ci-dessus, nous arrivons à lire depuis l'Arduino sur le port série. Ainsi, dès qu'un caractère est tapé au clavier, il est affiché sur la matrice de LEDs.&lt;br /&gt;
&lt;br /&gt;
=== Démonstration d'écriture sur le port série : ===&lt;br /&gt;
[[Fichier:Ecriture serie.mp4|centré|vignette|Ecriture serie]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nous sommes également capables d'écrire depuis le port série, les données sont envoyées depuis l'Arduino et afficher sur l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;.(ici nous renvoyons simplement le caractere tapé au clavier)&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numérique =&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était de concevoir et de créer un circuit imprimé (PCB) pour une carte écran LCD, englobant chaque étape du processus, depuis l'élaboration du schéma initial jusqu'à la programmation de l'affichage sur l'écran. &lt;br /&gt;
&lt;br /&gt;
Ainsi, cette partie abordera plus en détail les points suivants :&lt;br /&gt;
&lt;br /&gt;
# Réalisation du PCB&lt;br /&gt;
#* Schematic&lt;br /&gt;
#* Routage&lt;br /&gt;
#* Soudure&lt;br /&gt;
# Programmation de la carte électronique&lt;br /&gt;
#* Code, explications et tests&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
=== Partie 1 - réalisation du PCB : ===&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontrôleur Atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte-mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p certains ports n'étaient pas connectés aux endroits attendus. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustrer correctement le fonctionnement de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|vignette|Schematic final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi dû adapter notre routage pour qu'il corresponde avec notre carte une fois le circuit corrigé.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|vignette|Routage final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et tests : ====&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'Arduino en tant qu'ISP, mais nous obtenions une erreur. &lt;br /&gt;
Également, après un test en programmant directement la carte avec un programme simple en C et un ficher Makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer, mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précédemment, les connexions de l'AVR ISP étaient finalement en cause. Nous avons donc réussi à corriger le problème directement en câblant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|Partie supérieure[[Fichier:Partie supérieure carte écran .png|alt=Partie supérieure carte écran |centré|vignette|400x400px|Partie supérieure carte écran ]]&lt;br /&gt;
|Partie inférieure[[Fichier:Partie inféreure carte écran .png|alt=Partie inférieure carte écran |centré|vignette|400x400px|Partie inférieure carte écran ]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs). L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêchait d'afficher sur l'écran. Erreur certainement causée au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
Ainsi, nous avons pu tester le programme &amp;quot;blink&amp;quot; fourni dans l'Arduino IDE et constater que notre carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Partie 2 - Programmation de la carte électronique : ===&lt;br /&gt;
&lt;br /&gt;
Pour le code de la partie écran, nous avons un fichier LCD.c et LCD.h qui implémentent les fonctions permettant l'interaction avec l'écran. La fonction ''LCD_WriteText'' permet d'écrire une chaîne de caractères sur l'écran de manière à ce que le passage à la nouvelle ligne se fasse automatiquement.&lt;br /&gt;
&lt;br /&gt;
Le fichier main.c inclut le programme qui utilise LCD.h afin de faire fonctionner l’écran.&lt;br /&gt;
&lt;br /&gt;
Ainsi, nous pouvons programmer l'Atmega328p de notre carte électronique.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
    LCD_EraseScreen(2, 16);// Efface l'écran avant d'écrire dessus&lt;br /&gt;
&lt;br /&gt;
	LCD_WriteText(&amp;quot;test 123!&amp;quot;, 2, 16, &amp;amp;row, &amp;amp;col, second_line_buff, &amp;amp;second_line_index);// écriture initiale&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	_delay_ms(100);&lt;br /&gt;
	LCD_WriteText(&amp;quot; Hello! :)&amp;quot;, 2, 16, &amp;amp;row, &amp;amp;col, second_line_buff, &amp;amp;second_line_index);// écriture consecutive&lt;br /&gt;
	_delay_ms(50);&lt;br /&gt;
&lt;br /&gt;
	LCD_WriteText(&amp;quot;Now writing to much text so that the screen scrools down&amp;quot;, 2, 16, &amp;amp;row, &amp;amp;col, second_line_buff, &amp;amp;second_line_index);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Cela fait fonctionner l'écran comme sur la vidéo suivante:&lt;br /&gt;
[[Fichier:Ecran fonctionne.mp4|vignette|L'écran fonctionne|centré]]&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme la communication série ou encore les composants systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons eu certaines difficultés lors de la conception de notre PCB. Ces difficultés nous ont coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'Arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'Arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3187</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3187"/>
		<updated>2024-01-18T20:52:02Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Partie 2 - Programmation de la carte électronique : */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
Le détail de notre code et de notre routage est disponible sur notre git : https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // configuration sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // configuration entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                                  // Activer la communication&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;4);                                    // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                               // Désactiver la communication&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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 d'envoi&lt;br /&gt;
    return SPDR;                                         // octet reçu&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Comme il est possible de constater sur la vidéo ci-dessus, nous arrivons à lire depuis l'Arduino sur le port série. Ainsi, dès qu'un caractère est tapé au clavier, il est affiché sur la matrie de LEDs.&lt;br /&gt;
&lt;br /&gt;
=== Démonstration d'écriture sur le port série : ===&lt;br /&gt;
[[Fichier:Ecriture serie.mp4|centré|vignette|Ecriture serie]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nous sommes également capable d'écrire depuis le port série, les données sont envoyés depuis l'Arduino et afficher sur l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;.(ici nous renvoyons simplement le caractere tapé au clavier)&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numérique =&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était de concevoir et de créer un circuit imprimé (PCB) pour une carte écran LCD, englobant chaque étape du processus, depuis l'élaboration du schéma initial jusqu'à la programmation de l'affichage sur l'écran. &lt;br /&gt;
&lt;br /&gt;
Ainsi cette partie abordera plus en détail les points suivants :&lt;br /&gt;
&lt;br /&gt;
# Réalisation du PCB&lt;br /&gt;
#* Schematic&lt;br /&gt;
#* Routage&lt;br /&gt;
#* Soudure&lt;br /&gt;
# Programmation de la carte électronique&lt;br /&gt;
#* Code, explications et tests&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
=== Partie 1 - réalisation du PCB : ===&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontrôleur Atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p certains ports n'étaient pas connectés aux endroits attendus. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustrer correctement le fonctionnement de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|vignette|Schematic final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois le circuit corrigé.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|vignette|Routage final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et tests : ====&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'Arduino en tant qu'ISP, mais nous obtenions une erreur. &lt;br /&gt;
Également, après un test en programmant directement la carte avec un programme simple en C et un ficher Makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précédemment, les connexions de l'AVR ISP était finalement en cause. Nous avons donc réussi à corriger le problème directement en câblant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|Partie supérieure[[Fichier:Partie supérieure carte écran .png|alt=Partie supérieure carte écran |centré|vignette|400x400px|Partie supérieure carte écran ]]&lt;br /&gt;
|Partie inférieure[[Fichier:Partie inféreure carte écran .png|alt=Partie inférieure carte écran |centré|vignette|400x400px|Partie inférieure carte écran ]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs). L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
Ainsi, nous avons pu tester le programme &amp;quot;blink&amp;quot; fourni dans l'Arduino IDE et constater que notre carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Partie 2 - Programmation de la carte électronique : ===&lt;br /&gt;
&lt;br /&gt;
Pour le code de la partie écran, nous avons un fichier LCD.c et LCD.h qui implémentent les fonctions permettant l'interaction avec l'écran. La fonction ''LCD_WriteText'' permet d'écrire une chaîne de caractères sur l'écran de manière à ce que le passage à la nouvelle ligne se fasse automatiquement.&lt;br /&gt;
&lt;br /&gt;
Le fichier main.c inclut le programme qui utilise LCD.h afin de faire fonctionner l’écran.&lt;br /&gt;
&lt;br /&gt;
Ainsi, nous pouvons programmer l'Atmega328p de notre carte électronique.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
    LCD_EraseScreen(2, 16);// Efface l'écran avant d'écrire dessus&lt;br /&gt;
&lt;br /&gt;
	LCD_WriteText(&amp;quot;test 123!&amp;quot;, 2, 16, &amp;amp;row, &amp;amp;col, second_line_buff, &amp;amp;second_line_index);// écriture initiale&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	_delay_ms(100);&lt;br /&gt;
	LCD_WriteText(&amp;quot; Hello! :)&amp;quot;, 2, 16, &amp;amp;row, &amp;amp;col, second_line_buff, &amp;amp;second_line_index);// écriture consecutive&lt;br /&gt;
	_delay_ms(50);&lt;br /&gt;
&lt;br /&gt;
	LCD_WriteText(&amp;quot;Now writing to much text so that the screen scrools down&amp;quot;, 2, 16, &amp;amp;row, &amp;amp;col, second_line_buff, &amp;amp;second_line_index);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Cela fait fonctionner l'écran comme sur la vidéo suivante:&lt;br /&gt;
[[Fichier:Ecran fonctionne.mp4|vignette|L'écran fonctionne|centré]]&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme la communication série ou encore les composants systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons eu certaines difficultés lors de la conception de notre PCB. Ces difficultés nous ont coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'Arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'Arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3186</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3186"/>
		<updated>2024-01-18T20:39:09Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Partie 2 - Programmation de la carte électronique : */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // configuration sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // configuration entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                                  // Activer la communication&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;4);                                    // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                               // Désactiver la communication&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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 d'envoi&lt;br /&gt;
    return SPDR;                                         // octet reçu&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Comme il est possible de constater sur la vidéo ci-dessus, nous arrivons à lire depuis l'Arduino sur le port série. Ainsi, dès qu'un caractère est tapé au clavier, il est affiché sur la matrie de LEDs.&lt;br /&gt;
&lt;br /&gt;
=== Démonstration d'écriture sur le port série : ===&lt;br /&gt;
[[Fichier:Ecriture serie.mp4|centré|vignette|Ecriture serie]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nous sommes également capable d'écrire depuis le port série, les données sont envoyés depuis l'Arduino et afficher sur l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;.(ici nous renvoyons simplement le caractere tapé au clavier)&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numérique =&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était de concevoir et de créer un circuit imprimé (PCB) pour une carte écran LCD, englobant chaque étape du processus, depuis l'élaboration du schéma initial jusqu'à la programmation de l'affichage sur l'écran. &lt;br /&gt;
&lt;br /&gt;
Ainsi cette partie abordera plus en détail les points suivants :&lt;br /&gt;
&lt;br /&gt;
# Réalisation du PCB&lt;br /&gt;
#* Schematic&lt;br /&gt;
#* Routage&lt;br /&gt;
#* Soudure&lt;br /&gt;
# Programmation de la carte électronique&lt;br /&gt;
#* Code, explications et tests&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
=== Partie 1 - réalisation du PCB : ===&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontrôleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p certains ports n'étaient pas connectés aux endroits attendus. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustrer correctement le fonctionnement de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|vignette|Schematic final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois le circuit corrigé.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|vignette|Routage final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et tests : ====&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'Arduino en tant qu'ISP, mais nous obtenions une erreur. &lt;br /&gt;
Également, après un test en programmant directement la carte avec un programme simple en C et un ficher Makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précédemment, les connexions de l'AVR ISP était finalement en cause. Nous avons donc réussi à corriger le problème directement en câblant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|Partie supérieure[[Fichier:Partie supérieure carte écran .png|alt=Partie supérieure carte écran |centré|vignette|400x400px|Partie supérieure carte écran ]]&lt;br /&gt;
|Partie inférieure[[Fichier:Partie inféreure carte écran .png|alt=Partie inférieure carte écran |centré|vignette|400x400px|Partie inférieure carte écran ]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs). L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
Ainsi, nous avons pu tester le programme &amp;quot;blink&amp;quot; fourni dans l'Arduino IDE et constater que notre carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Partie 2 - Programmation de la carte électronique : ===&lt;br /&gt;
&lt;br /&gt;
Nous avons un fichier LCD.c et LCD.h avec des fonctions qui servent à interagir avec l'écran. La fonction LCD_WriteText qui permet d'écrire une chaîne de caractères sur l'écran de manière à ce que le passage à la nouvelle ligne se fasse automatiquement.&lt;br /&gt;
&lt;br /&gt;
Le fichier main.c contient le programe qui utilise LCD.h affin de faire fonctionner l'ecran.&lt;br /&gt;
&lt;br /&gt;
Nous pouvons programmer l'atmega situé sur notre carte.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
    LCD_EraseScreen(2, 16);// Efface l'écran avant d'écrire dessus&lt;br /&gt;
&lt;br /&gt;
	LCD_WriteText(&amp;quot;test 123!&amp;quot;, 2, 16, &amp;amp;row, &amp;amp;col, second_line_buff, &amp;amp;second_line_index);// écriture initiale&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	_delay_ms(100);&lt;br /&gt;
	LCD_WriteText(&amp;quot; Hello! :)&amp;quot;, 2, 16, &amp;amp;row, &amp;amp;col, second_line_buff, &amp;amp;second_line_index);// écriture consecutive&lt;br /&gt;
	_delay_ms(50);&lt;br /&gt;
&lt;br /&gt;
	LCD_WriteText(&amp;quot;Now writing to much text so that the screen scrools down&amp;quot;, 2, 16, &amp;amp;row, &amp;amp;col, second_line_buff, &amp;amp;second_line_index);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Cela fait fonctionner l'ecran comme sur la vidéo suivante:&lt;br /&gt;
[[Fichier:Ecran fonctionne.mp4|vignette|L'écran fonctionne|centré]]&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;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme la communication série ou encore les composants systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons eu certaines difficultés lors de la conception de notre PCB. Ces difficultés nous ont coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'Arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'Arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3057</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3057"/>
		<updated>2024-01-18T11:14:58Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Démonstration de lecture sur le port série : */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // configuration sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // configuration entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                                  // Activer la communication&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;4);                                    // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                               // Désactiver la communication&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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 d'envoi&lt;br /&gt;
    return SPDR;                                         // octet reçu&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Comme il est possible de constater sur la vidéo ci-dessus, nous arrivons à lire depuis l'Arduino sur le port série. Ainsi, dès qu'un caractère est tapé au clavier, il est affiché sur la matrie de LEDs.&lt;br /&gt;
&lt;br /&gt;
=== Démonstration d'écriture sur le port série : ===&lt;br /&gt;
[[Fichier:Ecriture serie.mp4|centré|vignette|Ecriture serie]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nous sommes également capable d'écrire depuis le port série, les données sont envoyés depuis l'Arduino et afficher sur l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numérique =&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était de concevoir et de créer un circuit imprimé (PCB) pour une carte écran LCD, englobant chaque étape du processus, depuis l'élaboration du schéma initial jusqu'à la programmation de l'affichage sur l'écran. &lt;br /&gt;
&lt;br /&gt;
Ainsi cette partie abordera plus en détail les points suivants :&lt;br /&gt;
&lt;br /&gt;
# Réalisation du PCB&lt;br /&gt;
#* Schematic&lt;br /&gt;
#* Routage&lt;br /&gt;
#* Soudure&lt;br /&gt;
# Programmation de la carte électronique&lt;br /&gt;
#* Code, explications et tests&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
=== Partie 1 - réalisation du PCB : ===&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontrôleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p certains ports n'étaient pas connectés aux endroits attendus. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustrer correctement le fonctionnement de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|vignette|Schematic final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois le circuit corrigé.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|vignette|Routage final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et tests : ====&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'Arduino en tant qu'ISP, mais nous obtenions une erreur. &lt;br /&gt;
Également, après un test en programmant directement la carte avec un programme simple en C et un ficher Makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précédemment, les connexions de l'AVR ISP était finalement en cause. Nous avons donc réussi à corriger le problème directement en câblant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|Partie supérieure[[Fichier:Partie supérieure carte écran .png|alt=Partie supérieure carte écran |centré|vignette|400x400px|Partie supérieure carte écran ]]&lt;br /&gt;
|Partie inférieure[[Fichier:Partie inféreure carte écran .png|alt=Partie inférieure carte écran |centré|vignette|400x400px|Partie inférieure carte écran ]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs). L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
Ainsi, nous avons pu tester le programme &amp;quot;blink&amp;quot; fourni dans l'Arduino IDE et constater que notre carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Partie 2 - Programmation de la carte électronique : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Code et explications&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme la communication série ou encore les composants systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons eu certaines difficultés lors de la conception de notre PCB. Ces difficultés nous ont coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'Arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'Arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3056</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3056"/>
		<updated>2024-01-18T11:14:17Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Démonstration de lecture sur le port série : */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // configuration sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // configuration entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                                  // Activer la communication&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;4);                                    // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                               // Désactiver la communication&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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 d'envoi&lt;br /&gt;
    return SPDR;                                         // octet reçu&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|centré]]Comme il est possible de constater sur la vidéo ci-dessus, nous arrivons à lire depuis l'Arduino sur le port série. Ainsi, dès qu'un caractère est tapé au clavier, il est affiché sur la matrie de LEDs.&lt;br /&gt;
&lt;br /&gt;
=== Démonstration d'écriture sur le port série : ===&lt;br /&gt;
[[Fichier:Ecriture serie.mp4|centré|vignette|Ecriture serie]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nous sommes également capable d'écrire depuis le port série, les données sont envoyés depuis l'Arduino et afficher sur l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numérique =&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était de concevoir et de créer un circuit imprimé (PCB) pour une carte écran LCD, englobant chaque étape du processus, depuis l'élaboration du schéma initial jusqu'à la programmation de l'affichage sur l'écran. &lt;br /&gt;
&lt;br /&gt;
Ainsi cette partie abordera plus en détail les points suivants :&lt;br /&gt;
&lt;br /&gt;
# Réalisation du PCB&lt;br /&gt;
#* Schematic&lt;br /&gt;
#* Routage&lt;br /&gt;
#* Soudure&lt;br /&gt;
# Programmation de la carte électronique&lt;br /&gt;
#* Code, explications et tests&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
=== Partie 1 - réalisation du PCB : ===&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontrôleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p certains ports n'étaient pas connectés aux endroits attendus. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustrer correctement le fonctionnement de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|vignette|Schematic final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois le circuit corrigé.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|vignette|Routage final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et tests : ====&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'Arduino en tant qu'ISP, mais nous obtenions une erreur. &lt;br /&gt;
Également, après un test en programmant directement la carte avec un programme simple en C et un ficher Makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précédemment, les connexions de l'AVR ISP était finalement en cause. Nous avons donc réussi à corriger le problème directement en câblant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|Partie supérieure[[Fichier:Partie supérieure carte écran .png|alt=Partie supérieure carte écran |centré|vignette|400x400px|Partie supérieure carte écran ]]&lt;br /&gt;
|Partie inférieure[[Fichier:Partie inféreure carte écran .png|alt=Partie inférieure carte écran |centré|vignette|400x400px|Partie inférieure carte écran ]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs). L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
Ainsi, nous avons pu tester le programme &amp;quot;blink&amp;quot; fourni dans l'Arduino IDE et constater que notre carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Partie 2 - Programmation de la carte électronique : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Code et explications&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme la communication série ou encore les composants systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons eu certaines difficultés lors de la conception de notre PCB. Ces difficultés nous ont coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'Arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'Arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Ecriture_serie.mp4&amp;diff=3054</id>
		<title>Fichier:Ecriture serie.mp4</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Ecriture_serie.mp4&amp;diff=3054"/>
		<updated>2024-01-18T11:10:29Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ecriture serie&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3051</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3051"/>
		<updated>2024-01-18T10:59:07Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // configuration sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // configuration entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_activer(void){                                  // Activer la communication&lt;br /&gt;
    PORTD &amp;amp;= ~(1&amp;lt;&amp;lt;4);                                    // Ligne SS à l'état bas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void spi_desactiver(void){                               // Désactiver la communication&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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 d'envoi&lt;br /&gt;
    return SPDR;                                         // octet reçu&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Comme il est possible de constater sur la vidéo ci-dessus, nous arrivons à lire depuis l'Arduino sur le port série. Ainsi, dès qu'un caractère est tapé au clavier, il est affiché sur la matrie de LEDs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numérique =&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était de concevoir et de créer un circuit imprimé (PCB) pour une carte écran LCD, englobant chaque étape du processus, depuis l'élaboration du schéma initial jusqu'à la programmation de l'affichage sur l'écran. &lt;br /&gt;
&lt;br /&gt;
Ainsi cette partie abordera plus en détail les points suivants :&lt;br /&gt;
&lt;br /&gt;
# Réalisation du PCB&lt;br /&gt;
#* Schematic&lt;br /&gt;
#* Routage&lt;br /&gt;
#* Soudure&lt;br /&gt;
# Programmation de la carte électronique&lt;br /&gt;
#* Code, explications et tests&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
=== Partie 1 - réalisation du PCB : ===&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontrôleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p certains ports n'étaient pas connectés aux endroits attendus. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustrer correctement le fonctionnement de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|vignette|Schematic final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois le circuit corrigé.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|vignette|Routage final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et tests : ====&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avions une erreur. &lt;br /&gt;
Également, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précédemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en câblant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|Partie supérieure[[Fichier:Partie supérieure carte écran .png|alt=Partie supérieure carte écran |centré|vignette|400x400px|Partie supérieure carte écran ]]&lt;br /&gt;
|Partie inférieure[[Fichier:Partie inféreure carte écran .png|alt=Partie inférieure carte écran |centré|vignette|400x400px|Partie inférieure carte écran ]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs). L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
Ainsi, nous avons pu tester le programme &amp;quot;blink&amp;quot; fourni dans l'Arduino IDE et constater que notre carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Partie 2 - Programmation de la carte électronique : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Code et explications&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme la communication série ou encore les composants systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons eu certaines difficultés lors de la conception de notre PCB. Ces difficultés nous ont coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3043</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3043"/>
		<updated>2024-01-18T10:14:10Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Partie 2 - Programmation de la carte électronique : */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){                                     // Initialisation du bus SPI&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // Définition des sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);                             // Désactivation du périphérique&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&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;4);                                    // 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;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Comme il est possible de constater sur la vidéo ci-dessus, nous arrivons à lire depuis l'Arduino sur le port série. Ainsi, dès qu'un caractère est tapé au clavier, il est affiché sur la matrie de LEDs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numérique =&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était de concevoir et de créer un circuit imprimé (PCB) pour une carte écran LCD, englobant chaque étape du processus, depuis l'élaboration du schéma initial jusqu'à la programmation de l'affichage sur l'écran. &lt;br /&gt;
&lt;br /&gt;
Ainsi cette partie abordera plus en détail les points suivants :&lt;br /&gt;
&lt;br /&gt;
# Réalisation du PCB&lt;br /&gt;
#* Schematic&lt;br /&gt;
#* Routage&lt;br /&gt;
#* Soudure&lt;br /&gt;
# Programmation de la carte électronique&lt;br /&gt;
#* Code, explications et tests&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
=== Partie 1 - réalisation du PCB : ===&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontrôleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p certains ports n'étaient pas connectés aux endroits attendus. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustrer correctement le fonctionnement de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|vignette|Schematic final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois le circuit corrigé.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|vignette|Routage final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et tests : ====&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avions une erreur. &lt;br /&gt;
Également, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précédemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en câblant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|Partie supérieure[[Fichier:Partie supérieure carte écran .png|alt=Partie supérieure carte écran |centré|vignette|400x400px|Partie supérieure carte écran ]]&lt;br /&gt;
|Partie inférieure[[Fichier:Partie inféreure carte écran .png|alt=Partie inférieure carte écran |centré|vignette|400x400px|Partie inférieure carte écran ]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs). L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
Ainsi, nous avons pu tester le programme &amp;quot;blink&amp;quot; fourni dans l'Arduino IDE et constater que notre carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Partie 2 - Programmation de la carte électronique : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Code et explications&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme la communication série ou encore les composants systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons eu certaines difficultés lors de la conception de notre PCB. Ces difficultés nous ont coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3038</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3038"/>
		<updated>2024-01-18T09:51:39Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Démonstration de lecture sur le port série : */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){                                     // Initialisation du bus SPI&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // Définition des sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);                             // Désactivation du périphérique&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&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;4);                                    // 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;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Comme il est possible de constater sur la vidéo ci-dessus, nous arrivons à lire depuis l'Arduino sur le port série. Ainsi, dès qu'un caractère est tapé au clavier, il est affiché sur la matrie de LEDs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numérique =&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était de concevoir et de créer un circuit imprimé (PCB) pour une carte écran LCD, englobant chaque étape du processus, depuis l'élaboration du schéma initial jusqu'à la programmation de l'affichage sur l'écran. &lt;br /&gt;
&lt;br /&gt;
Ainsi cette partie abordera plus en détail les points suivants :&lt;br /&gt;
&lt;br /&gt;
# Réalisation du PCB&lt;br /&gt;
#* Schematic&lt;br /&gt;
#* Routage&lt;br /&gt;
#* Soudure&lt;br /&gt;
# Programmation de la carte électronique&lt;br /&gt;
#* Code, explications et tests&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
=== Partie 1 - réalisation du PCB : ===&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontrôleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|vignette|Schematic final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois le circuit corrigé.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|vignette|Routage final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et tests : ====&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avions une erreur. &lt;br /&gt;
Également, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précédemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en câblant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|Partie supérieure[[Fichier:Partie supérieure carte écran .png|alt=Partie supérieure carte écran |centré|vignette|400x400px|Partie supérieure carte écran ]]&lt;br /&gt;
|Partie inférieure[[Fichier:Partie inféreure carte écran .png|alt=Partie inférieure carte écran |centré|vignette|400x400px|Partie inférieure carte écran ]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs). L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
Ainsi, nous avons pu tester le programme &amp;quot;blink&amp;quot; fourni dans l'Arduino IDE et constater que notre carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Partie 2 - Programmation de la carte électronique : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Code et explications&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme la communication série ou encore les composants systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons commis une erreur lors de la conception de notre PCB. Cette erreur nous à énormément coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3035</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3035"/>
		<updated>2024-01-18T09:48:29Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Soudures et tests : */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){                                     // Initialisation du bus SPI&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // Définition des sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);                             // Désactivation du périphérique&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&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;4);                                    // 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;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numérique =&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était de concevoir et de créer un circuit imprimé (PCB) pour une carte écran LCD, englobant chaque étape du processus, depuis l'élaboration du schéma initial jusqu'à la programmation de l'affichage sur l'écran. &lt;br /&gt;
&lt;br /&gt;
Ainsi cette partie abordera plus en détail les points suivants :&lt;br /&gt;
&lt;br /&gt;
# Réalisation du PCB&lt;br /&gt;
#* Schematic&lt;br /&gt;
#* Routage&lt;br /&gt;
#* Soudure&lt;br /&gt;
# Programmation de la carte électronique&lt;br /&gt;
#* Code, explications et tests&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
=== Partie 1 - réalisation du PCB : ===&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontrôleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|vignette|Schematic final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois le circuit corrigé.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|vignette|Routage final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et tests : ====&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avions une erreur. &lt;br /&gt;
Également, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précédemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en câblant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|Partie supérieure[[Fichier:Partie supérieure carte écran .png|alt=Partie supérieure carte écran |centré|vignette|400x400px|Partie supérieure carte écran ]]&lt;br /&gt;
|Partie inférieure[[Fichier:Partie inféreure carte écran .png|alt=Partie inférieure carte écran |centré|vignette|400x400px|Partie inférieure carte écran ]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs). L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
Ainsi, nous avons pu tester le programme &amp;quot;blink&amp;quot; fourni dans l'Arduino IDE et constater que notre carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Partie 2 - Programmation de la carte électronique : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Code et explications&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme la communication série ou encore les composants systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons commis une erreur lors de la conception de notre PCB. Cette erreur nous à énormément coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3032</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3032"/>
		<updated>2024-01-18T09:45:34Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Soudures et tests : */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){                                     // Initialisation du bus SPI&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // Définition des sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);                             // Désactivation du périphérique&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&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;4);                                    // 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;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numérique =&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était de concevoir et de créer un circuit imprimé (PCB) pour une carte écran LCD, englobant chaque étape du processus, depuis l'élaboration du schéma initial jusqu'à la programmation de l'affichage sur l'écran. &lt;br /&gt;
&lt;br /&gt;
Ainsi cette partie abordera plus en détail les points suivants :&lt;br /&gt;
&lt;br /&gt;
# Réalisation du PCB&lt;br /&gt;
#* Schematic&lt;br /&gt;
#* Routage&lt;br /&gt;
#* Soudure&lt;br /&gt;
# Programmation de la carte électronique&lt;br /&gt;
#* Code, explications et tests&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
=== Partie 1 - réalisation du PCB : ===&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontrôleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|vignette|Schematic final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois le circuit corrigé.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|vignette|Routage final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et tests : ====&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avions une erreur. &lt;br /&gt;
Également, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précédemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en câblant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|Partie supérieure[[Fichier:Partie supérieure carte écran .png|alt=Partie supérieure carte écran |centré|vignette|400x400px|Partie supérieure carte écran ]]&lt;br /&gt;
|Partie inférieure[[Fichier:Partie inféreure carte écran .png|alt=Partie inférieure carte écran |centré|vignette|400x400px|Partie inférieure carte écran ]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs). L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Partie 2 - Programmation de la carte électronique : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Code et explications&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme la communication série ou encore les composants systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons commis une erreur lors de la conception de notre PCB. Cette erreur nous à énormément coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3031</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3031"/>
		<updated>2024-01-18T09:44:28Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Soudures et tests : */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){                                     // Initialisation du bus SPI&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // Définition des sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);                             // Désactivation du périphérique&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&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;4);                                    // 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;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numérique =&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était de concevoir et de créer un circuit imprimé (PCB) pour une carte écran LCD, englobant chaque étape du processus, depuis l'élaboration du schéma initial jusqu'à la programmation de l'affichage sur l'écran. &lt;br /&gt;
&lt;br /&gt;
Ainsi cette partie abordera plus en détail les points suivants :&lt;br /&gt;
&lt;br /&gt;
# Réalisation du PCB&lt;br /&gt;
#* Schematic&lt;br /&gt;
#* Routage&lt;br /&gt;
#* Soudure&lt;br /&gt;
# Programmation de la carte électronique&lt;br /&gt;
#* Code, explications et tests&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
=== Partie 1 - réalisation du PCB : ===&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontrôleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|vignette|Schematic final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois le circuit corrigé.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|vignette|Routage final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et tests : ====&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avions une erreur. &lt;br /&gt;
Également, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précédemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en câblant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|Partie supérieure[[Fichier:Partie supérieure carte écran .png|alt=Partie supérieure carte écran |centré|vignette|400x400px|Partie supérieure carte écran ]]&lt;br /&gt;
|Partie inférieure[[Fichier:Partie inféreure carte écran .png|alt=Partie inférieure carte écran |centré|vignette|400x400px|Partie inférieure carte écran ]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Partie 2 - Programmation de la carte électronique : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Code et explications&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme la communication série ou encore les composants systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons commis une erreur lors de la conception de notre PCB. Cette erreur nous à énormément coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3030</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3030"/>
		<updated>2024-01-18T09:42:38Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Soudures et tests : */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){                                     // Initialisation du bus SPI&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // Définition des sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);                             // Désactivation du périphérique&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&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;4);                                    // 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;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numérique =&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était de concevoir et de créer un circuit imprimé (PCB) pour une carte écran LCD, englobant chaque étape du processus, depuis l'élaboration du schéma initial jusqu'à la programmation de l'affichage sur l'écran. &lt;br /&gt;
&lt;br /&gt;
Ainsi cette partie abordera plus en détail les points suivants :&lt;br /&gt;
&lt;br /&gt;
# Réalisation du PCB&lt;br /&gt;
#* Schematic&lt;br /&gt;
#* Routage&lt;br /&gt;
#* Soudure&lt;br /&gt;
# Programmation de la carte électronique&lt;br /&gt;
#* Code, explications et tests&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
=== Partie 1 - réalisation du PCB : ===&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontrôleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|vignette|Schematic final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois le circuit corrigé.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|vignette|Routage final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et tests : ====&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Également, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précédemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en câblant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|Partie supérieure[[Fichier:Partie supérieure carte écran .png|alt=Partie supérieure carte écran |centré|vignette|400x400px|Partie supérieure carte écran ]]&lt;br /&gt;
|Partie inférieure[[Fichier:Partie inféreure carte écran .png|alt=Partie inférieure carte écran |centré|vignette|400x400px|Partie inférieure carte écran ]]&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;
&lt;br /&gt;
&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Partie 2 - Programmation de la carte électronique : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Code et explications&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme la communication série ou encore les composants systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons commis une erreur lors de la conception de notre PCB. Cette erreur nous à énormément coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3029</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3029"/>
		<updated>2024-01-18T09:38:05Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Soudures et programmation : */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){                                     // Initialisation du bus SPI&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // Définition des sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);                             // Désactivation du périphérique&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&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;4);                                    // 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;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numérique =&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était de concevoir et de créer un circuit imprimé (PCB) pour une carte écran LCD, englobant chaque étape du processus, depuis l'élaboration du schéma initial jusqu'à la programmation de l'affichage sur l'écran. &lt;br /&gt;
&lt;br /&gt;
Ainsi cette partie abordera plus en détail les points suivants :&lt;br /&gt;
&lt;br /&gt;
# Réalisation du PCB&lt;br /&gt;
#* Schematic&lt;br /&gt;
#* Routage&lt;br /&gt;
#* Soudure&lt;br /&gt;
# Programmation de la carte électronique&lt;br /&gt;
#* Code, explications et tests&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
=== Partie 1 - réalisation du PCB : ===&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontrôleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|vignette|Schematic final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois le circuit corrigé.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|vignette|Routage final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Également, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précédemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en câblant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;br /&gt;
[[Fichier:Partie supérieure carte écran .png|alt=Partie supérieure carte écran |centré|vignette|400x400px|Partie supérieure carte écran ]]&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;
&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Partie 2 - Programmation de la carte électronique : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Code et explications&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme la communication série ou encore les composants systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons commis une erreur lors de la conception de notre PCB. Cette erreur nous à énormément coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Partie_inf%C3%A9reure_carte_%C3%A9cran_.png&amp;diff=3028</id>
		<title>Fichier:Partie inféreure carte écran .png</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Partie_inf%C3%A9reure_carte_%C3%A9cran_.png&amp;diff=3028"/>
		<updated>2024-01-18T09:35:43Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Partie inféreure carte écran&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Partie_sup%C3%A9rieure_carte_%C3%A9cran_.png&amp;diff=3026</id>
		<title>Fichier:Partie supérieure carte écran .png</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Partie_sup%C3%A9rieure_carte_%C3%A9cran_.png&amp;diff=3026"/>
		<updated>2024-01-18T09:34:49Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Partie supérieure carte écran&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3025</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3025"/>
		<updated>2024-01-18T09:29:54Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Carte électronique numerique */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){                                     // Initialisation du bus SPI&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // Définition des sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);                             // Désactivation du périphérique&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&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;4);                                    // 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;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numérique =&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était de concevoir et de créer un circuit imprimé (PCB) pour une carte écran LCD, englobant chaque étape du processus, depuis l'élaboration du schéma initial jusqu'à la programmation de l'affichage sur l'écran. &lt;br /&gt;
&lt;br /&gt;
Ainsi cette partie abordera plus en détail les points suivants :&lt;br /&gt;
&lt;br /&gt;
# Réalisation du PCB&lt;br /&gt;
#* Schematic&lt;br /&gt;
#* Routage&lt;br /&gt;
#* Soudure&lt;br /&gt;
# Programmation de la carte électronique&lt;br /&gt;
#* Code, explications et tests&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
=== Partie 1 - réalisation du PCB : ===&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontrôleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|vignette|Schematic final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois le circuit corrigé.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|vignette|Routage final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Également, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précédemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en câblant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]][[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]]&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;
&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Partie 2 - Programmation de la carte électronique : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Code et explications&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme la communication série ou encore les composants systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons commis une erreur lors de la conception de notre PCB. Cette erreur nous à énormément coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3024</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3024"/>
		<updated>2024-01-18T09:21:16Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Soudures et programmation : */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){                                     // Initialisation du bus SPI&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // Définition des sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);                             // Désactivation du périphérique&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&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;4);                                    // 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;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
=== Partie 1 - réalisation du PCB : ===&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|vignette|Schematic final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois le circuit corrigé.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|vignette|Routage final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]][[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]]&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;
&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Partie 2 - Programmation de la carte électronique : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Code et explications&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme la communication série ou encore les composants systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons commis une erreur lors de la conception de notre PCB. Cette erreur nous à énormément coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3023</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3023"/>
		<updated>2024-01-18T09:18:53Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Routage : */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){                                     // Initialisation du bus SPI&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // Définition des sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);                             // Désactivation du périphérique&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&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;4);                                    // 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;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
=== Partie 1 - réalisation du PCB : ===&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|vignette|Schematic final|centré|600x600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois le circuit corrigé.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|vignette|Routage final|centré|600x600px]]&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;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&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;
[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|néant]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
=== Partie 2 - Programmation de la carte électronique : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Code et explications&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme la communication série ou encore les composants systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons commis une erreur lors de la conception de notre PCB. Cette erreur nous à énormément coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3022</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3022"/>
		<updated>2024-01-18T09:12:02Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Bilan du projet */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){                                     // Initialisation du bus SPI&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // Définition des sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);                             // Désactivation du périphérique&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&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;4);                                    // 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;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
=== Partie 1 - réalisation du PCB : ===&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Schematic initial]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Schematic final]]&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&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;
[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|néant]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
=== Partie 2 - Programmation de la carte électronique : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Code et explications&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme la communication série ou encore les composants systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons commis une erreur lors de la conception de notre PCB. Cette erreur nous à énormément coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3010</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3010"/>
		<updated>2024-01-18T01:14:09Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Carte fille écran LCD */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){                                     // Initialisation du bus SPI&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // Définition des sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);                             // Désactivation du périphérique&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&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;4);                                    // 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;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
=== Partie 1 - réalisation du PCB : ===&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Schematic initial]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Schematic final]]&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&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;
[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|néant]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
=== Partie 2 - Programmation de la carte électronique : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Code et explications&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme les composantes systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons commis une erreur importante lors de la conception de notre PCB. Cette erreur nous à énormément coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3009</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3009"/>
		<updated>2024-01-18T01:11:00Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){                                     // Initialisation du bus SPI&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // Définition des sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);                             // Désactivation du périphérique&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&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;4);                                    // 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;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Schematic initial]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Schematic final]]&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&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;
[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|néant]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme les composantes systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons commis une erreur importante lors de la conception de notre PCB. Cette erreur nous à énormément coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3008</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3008"/>
		<updated>2024-01-18T01:07:52Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Bilan du projet */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){                                     // Initialisation du bus SPI&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // Définition des sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);                             // Désactivation du périphérique&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&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;4);                                    // 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;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Schematic initial]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Schematic final]]&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|néant]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme les composantes systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordée était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins, nous avons commis une erreur importante lors de la conception de notre PCB. Cette erreur nous à énormément coûté en termes de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnelle et avancer sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire minicom ou sur le terminal depuis l'arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3007</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3007"/>
		<updated>2024-01-18T01:04:37Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Soudures et programmation : */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){                                     // Initialisation du bus SPI&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // Définition des sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);                             // Désactivation du périphérique&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&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;4);                                    // 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;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Schematic initial]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Schematic final]]&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|néant]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme les composantes systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordé était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins nous avons commis une erreur importante lors de la conception de notre PCB. Cette erreur nous à énormément coutés en terme de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnel et avancé sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;ou sur le terminal depuis l'arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3006</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3006"/>
		<updated>2024-01-18T01:04:13Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){                                     // Initialisation du bus SPI&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // Définition des sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);                             // Désactivation du périphérique&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&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;4);                                    // 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;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Schematic initial]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Schematic final]]&lt;br /&gt;
Après le point d'avancement, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|néant]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précédemment.&lt;br /&gt;
&lt;br /&gt;
= Bilan du projet =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ce TP / Projet nous a permis d'aborder de nombreux point intéressants et d'en découvrir davantage sur plusieurs aspects majeurs comme les composantes systèmes, avec l'ordonnanceur notamment.  &lt;br /&gt;
&lt;br /&gt;
La première partie que nous avons abordé était la réalisation de la carte PCB pour notre futur carte électronique. Nous avions d'ores et déjà abordé ce sujet l'année dernière, néanmoins nous avons commis une erreur importante lors de la conception de notre PCB. Cette erreur nous à énormément coutés en terme de temps, mais nous avons su rebondir et faire les adaptations nécessaires pour obtenir une carte fonctionnel et avancé sur la suite du projet.&lt;br /&gt;
&lt;br /&gt;
Nous avons consacré la majeur partie de notre temps à établir un ordonnanceur fonctionnel et opérationnel pour les différentes tâches suivant sa réalisation. Ce fut assez complexe mais réellement instructif. Nous avons pu également, réaliser la programmation de la carte écran afin de de pouvoir interagir avec l'écran et afficher des caractères sur ce dernier.&lt;br /&gt;
&lt;br /&gt;
Malgré une première partie de projet compliquée, nous avons su nous investir davantage et redoubler d'efforts afin de pouvoir remplir nos objectifs. Ainsi, nous avons réussi à proposer une carte écran fonctionnelle, mais aussi un ordonnanceur et des fonctionnalités permettant une communication série entre notre machine et l'arduino. Ceci, afin d'afficher des caractères sur une matrice de LEDs depuis un utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;ou sur le terminal depuis l'arduino.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3005</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3005"/>
		<updated>2024-01-18T00:38:13Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Connexion SPI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|vignette|néant]]&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;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){                                     // Initialisation du bus SPI&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // Définition des sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);                             // Désactivation du périphérique&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&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;4);                                    // 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;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Schematic initial]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Schematic final]]&lt;br /&gt;
Après le point d'avancement avec les professeurs, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précedemment.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3004</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3004"/>
		<updated>2024-01-18T00:35:04Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : /* Démonstration de lecture sur le port série : */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|gauche|vignette]]&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;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){                                     // Initialisation du bus SPI&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // Définition des sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);                             // Désactivation du périphérique&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&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;4);                                    // 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;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série|néant]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Schematic initial]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Schematic final]]&lt;br /&gt;
Après le point d'avancement avec les professeurs, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précedemment.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3003</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=3003"/>
		<updated>2024-01-18T00:34:25Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&lt;br /&gt;
&lt;br /&gt;
Également, nous ont été fourni les connecteurs pour l'afficheur 7 segments et la matrice de LEDS &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmation de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteint une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ensuite ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers la matrice de LEDs afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|gauche|vignette]]&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;
Le bus SPI est utilisé pour la communication série synchrone entre plusieurs périphériques. Nous avons donc premièrement implémenté une fonction d'initialisation qui configure le bus SPI, les broches définies comme entrées ou sorties, et la fréquence d'horloge.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void spi_init(void){                                     // Initialisation du bus SPI&lt;br /&gt;
    SPI_DDR |= (1&amp;lt;&amp;lt;SPI_MOSI)|(1&amp;lt;&amp;lt;SPI_SCK);               // Définition des sorties&lt;br /&gt;
    SPI_DDR &amp;amp;= ~(1&amp;lt;&amp;lt;SPI_MISO);                           // Définition de l'entrée&lt;br /&gt;
    DDRD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    PORTD |= (1&amp;lt;&amp;lt;4);&lt;br /&gt;
    SPI_PORT |= (1&amp;lt;&amp;lt;SPI_SS);                             // Désactivation du périphérique&lt;br /&gt;
    SPCR = (1&amp;lt;&amp;lt;SPE)|(1&amp;lt;&amp;lt;MSTR)|(1&amp;lt;&amp;lt;SPR1);                 // Activation SPI (SPE) en état maître (MSTR)&lt;br /&gt;
                                                         // horloge F_CPU/64 (SPR1=1,SPR0=0)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Les fonctions d'activation/désactivation de la communication en série sont gérée par la mise à l'état haut ou bas de la ligne Slave Select.&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;4);                                    // 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;4);                                     // Ligne SS à l'état haut&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
La fonction principal qui permet l'échange de données sur le bus spi est la fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt;. La fonction &amp;lt;code&amp;gt;spi_echange&amp;lt;/code&amp;gt; effectue le transfert d'octet sur le bus SPI en plaçant la valeur de l'octet dans le registre de données SPI (&amp;lt;code&amp;gt;SPDR&amp;lt;/code&amp;gt;), puis en attendant la fin du transfert avant de renvoyer l'octet reçu.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;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;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Communication série : Matrice de LEDs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'objectif de cette partie était d'établir et gérer une connexion série avec la carte Arduino, c'est-à-dire de pouvoir lire ou envoyer des données entre la carte et un terminal grâce à une interface en ligne de commande. Nous avons donc ici utiliser l'utilitaire &amp;lt;code&amp;gt;minicom&amp;lt;/code&amp;gt;. Nous avons également implémenté des fonctions utilisant l'UART puisque la communication série est effectuée de manière asynchrone.&lt;br /&gt;
&lt;br /&gt;
=== Configuration de l'UART : ===&lt;br /&gt;
L'UART (Universal Asynchronous Receiver/Transmitter) est un protocole de communication qui permet d'établir des liaisons série et permet la transmission de données série asynchrones, ce qui signifie que les données sont transmises sans utiliser une horloge commune entre l'émetteur et le récepteur.&lt;br /&gt;
&lt;br /&gt;
La première fonction ci-dessous correspond donc à l'initialisation de l'UART :&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void init_serie(int speed)&lt;br /&gt;
{&lt;br /&gt;
    // Défini baud rate&lt;br /&gt;
    UBRR0 = F_CPU / (((unsigned long int)speed) &amp;lt;&amp;lt; 4) - 1;&lt;br /&gt;
&lt;br /&gt;
    UCSR0B = (1 &amp;lt;&amp;lt; TXEN0 | 1 &amp;lt;&amp;lt; RXEN0);   // Active le module de transmission et réception&lt;br /&gt;
&lt;br /&gt;
    UCSR0C = (1 &amp;lt;&amp;lt; UCSZ01 | 1 &amp;lt;&amp;lt; UCSZ00); // Configure taille de données sur 8 bits&lt;br /&gt;
&lt;br /&gt;
    UCSR0A &amp;amp;= ~(1 &amp;lt;&amp;lt; U2X0); // No double-speed&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Pour communiquer avec l'UART, on implémente également les fonctions &amp;lt;code&amp;gt;send_serie&amp;lt;/code&amp;gt; et  &amp;lt;code&amp;gt;get_serie&amp;lt;/code&amp;gt;. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void send_serie(char c)&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, UDRE0); // Boucle d'attente d'info du registre de contrôle pour envoi de donnée&lt;br /&gt;
    UDR0 = c; // écrit un caractère dans le registre UDR0&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
char get_serie()&lt;br /&gt;
{&lt;br /&gt;
    sem_P(SERIAL_COM);&lt;br /&gt;
    loop_until_bit_is_set(UCSR0A, RXC0);&lt;br /&gt;
    sem_V(SERIAL_COM);&lt;br /&gt;
    return UDR0; // renvoie le caractère reçu stocké dans le registre UDR0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Afin de synchroniser l'échange de données et éviter les problèmes de synchronisation sur la liaison série, nous utilisons des sémaphores (voir &amp;lt;code&amp;gt;semaphore.c&amp;lt;/code&amp;gt; sur le dépôt git).&lt;br /&gt;
&lt;br /&gt;
=== Démonstration de lecture sur le port série : ===&lt;br /&gt;
[[Fichier:Lecture série.mp4|vignette|Lecture série]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Par manque de temps, nous n'avons malheureusement pas pu réaliser cette partie.&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Schematic initial]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Schematic final]]&lt;br /&gt;
Après le point d'avancement avec les professeurs, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précedemment.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Lecture_s%C3%A9rie.mp4&amp;diff=3002</id>
		<title>Fichier:Lecture série.mp4</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Lecture_s%C3%A9rie.mp4&amp;diff=3002"/>
		<updated>2024-01-18T00:33:53Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Lecture série&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2679</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2679"/>
		<updated>2024-01-14T21:41:21Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&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 de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteind une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers l’écran afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|gauche|vignette]]&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Schematic initial]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Schematic final]]&lt;br /&gt;
Après le point d'avancement avec les professeurs, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précedemment.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2678</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2678"/>
		<updated>2024-01-14T21:40:54Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&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 de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteind une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
== Connexion SPI ==&lt;br /&gt;
Nous avons ajouté les fonctionnalités de communication sur le bus SPI.&lt;br /&gt;
&lt;br /&gt;
Cela nous permet notamment de communiquer de l’ordonnanceur vers l’écran afin d'y afficher quelque chose.&lt;br /&gt;
&lt;br /&gt;
Comme sur l'exemple ci-dessous :&lt;br /&gt;
[[Fichier:New.mp4|gauche|vignette]]&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;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Schematic initial]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Schematic final]]&lt;br /&gt;
Après le point d'avancement avec les professeurs, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précedemment.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2583</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2583"/>
		<updated>2023-12-21T11:14:54Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : Partie ordonnanceur avancée&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&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 de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
=== Première approche : ===&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 2 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteind une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, ces fonctions utilisent la fonction _delay_ms pour maintenir les LEDs allumés pendant un certain temps. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
=== Approche avancée : ===&lt;br /&gt;
Nous avons ensuite cherché à implémenter une fonction faisant office de pause, mais qui contrairement au delay, n'agissait pas comme une interruption à tout le programme. La fonction ''wait_ms'' permet de mettre une tâche en attente pendant un certain nombre de millisecondes.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void wait_ms(int ms){&lt;br /&gt;
    cli();&lt;br /&gt;
    taskList[currentTask].timer = ms;&lt;br /&gt;
    taskList[currentTask].state = SLEEPING;&lt;br /&gt;
    TCNT1 = 0;&lt;br /&gt;
    sei();&lt;br /&gt;
    TIMER1_COMPA_vect();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Le timer de la tâche prend la valeur en milliseconde spécifié dans l'argument de la fonction et la fonction passe en état de sommeil. Dans le programme, la fonction TCNT1 permet de mesurer le temps écoulé depuis l'appel à la fonction ''wait_ms'', elle est donc ici fixée à 0. On fait ensuite directement appel à la routine d'interruption pour déclencher le mécanisme de gestion du temps.&lt;br /&gt;
&lt;br /&gt;
La routine d'interruption du Timer1 est implémentée de telle sorte que le contexte de la tâche en cours est sauvegardé, l'ordonnanceur est appelé, puis le contexte de la prochaine tâche à exécuter est restauré.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
ISR(TIMER1_COMPA_vect, ISR_NAKED)&lt;br /&gt;
{&lt;br /&gt;
  // Sauvegarde du contexte de la tâche interrompue&lt;br /&gt;
  portSAVE_CONTEXT();&lt;br /&gt;
  // Sauvegarde la valeur actuelle du pointeur de pile (SP)&lt;br /&gt;
  taskList[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 = taskList[currentTask].stackPointer;&lt;br /&gt;
  // restaure les valeurs des registres depuis la pile.&lt;br /&gt;
  portRESTORE_CONTEXT();&lt;br /&gt;
  // return from interupt&lt;br /&gt;
  asm volatile ( &amp;quot;reti&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La fonction scheduler, commentée ci-dessous, permet de gérer l'ordonnancement des tâches en fonction de leur temps d'attente défini.&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
    for(int i = 0; i &amp;lt; NUM_TASKS; i++){// Pour chaque tâche&lt;br /&gt;
        if(taskList[i].state == SLEEPING){ // Si elle est en état SLEEPING&lt;br /&gt;
            uint16_t time_elapsed = 20;&lt;br /&gt;
              if(TCNT1 != 0){ // Le timer a commencé à compter&lt;br /&gt;
                  time_elapsed = TCNT1 * 200 / OCR1A / 10; // Temps en milliseconde écoulé depuis la dernière interruption&lt;br /&gt;
                  TCNT1 = 0; // Réinitialisation du timer pour la prochaine interruption&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              taskList[i].timer = taskList[i].timer - time_elapsed;&lt;br /&gt;
&lt;br /&gt;
              if(taskList[i].timer == 0) // Fin du timer&lt;br /&gt;
              {&lt;br /&gt;
                taskList[i].state = RUNNING; // La tâche se réveille&lt;br /&gt;
              }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Permet de sélectionner la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
    do{&lt;br /&gt;
        currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
    }while(taskList[currentTask].state == SLEEPING);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme complet et détaillé de notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Schematic initial]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Schematic final]]&lt;br /&gt;
Après le point d'avancement avec les professeurs, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précedemment.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2577</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2577"/>
		<updated>2023-12-21T10:16:52Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&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 de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 3 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteind une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, et le troisième processus ne fait rien pour notre démonstration. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme détaillé de  notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Schematic initial]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Schematic final]]&lt;br /&gt;
Après le point d'avancement avec les professeurs, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précedemment.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2576</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2576"/>
		<updated>2023-12-21T10:15:21Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&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 de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 3 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteind une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, et le troisième processus ne fait rien pour notre démonstration. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme détaillé de  notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Carte écran schematic]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Carte fille ecran LCD]]&lt;br /&gt;
Après le point d'avancement avec les professeurs, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précedemment.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2575</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2575"/>
		<updated>2023-12-21T10:15:09Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&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 de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 3 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteind une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, et le troisième processus ne fait rien pour notre démonstration. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme détaillé de  notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Carte écran schematic]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Carte fille ecran LCD]]&lt;br /&gt;
Après le point d'avancement avec les professeurs, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précedemment.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2574</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2574"/>
		<updated>2023-12-21T10:14:51Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&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 de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 3 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteind une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, et le troisième processus ne fait rien pour notre démonstration. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme détaillé de  notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Carte écran schematic]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Carte fille ecran LCD]]&lt;br /&gt;
Après le point d'avancement avec les professeurs, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&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;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précedemment.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2573</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2573"/>
		<updated>2023-12-21T10:14:36Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&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 de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 3 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteind une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, et le troisième processus ne fait rien pour notre démonstration. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme détaillé de  notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Carte écran schematic]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Carte fille ecran LCD]]&lt;br /&gt;
Après le point d'avancement avec les professeurs, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&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;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précedemment.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2572</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2572"/>
		<updated>2023-12-21T10:14:09Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&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 de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 3 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteind une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, et le troisième processus ne fait rien pour notre démonstration. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme détaillé de  notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Carte écran schematic]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Carte fille ecran LCD]]&lt;br /&gt;
Après le point d'avancement avec les professeurs, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&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;
==== Routage : ====&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précedemment.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2571</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2571"/>
		<updated>2023-12-21T10:13:47Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&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 de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 3 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteind une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, et le troisième processus ne fait rien pour notre démonstration. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme détaillé de  notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Carte écran schematic]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Carte fille ecran LCD]]&lt;br /&gt;
Après le point d'avancement avec les professeurs, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&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;
==== Routage : ====&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran|267x267px]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran |267x267px]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précedemment.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2570</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2570"/>
		<updated>2023-12-21T10:12:17Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&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 de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 3 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteind une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, et le troisième processus ne fait rien pour notre démonstration. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme détaillé de  notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Carte écran schematic]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Carte fille ecran LCD]]&lt;br /&gt;
Après le point d'avancement avec les professeurs, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&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;
==== Routage : ====&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran]][[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran ]]Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
L'un des pins du connecteur femelle (16 pins) sur la carte n'était pas correctement relié à la masse et nous empêché d'afficher sur l'écran. Erreur certainement causé au moment de la création du plan de masse, mais finalement corrigée en soudant un fil sur le dessous de la carte de la même manière que précedemment.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2569</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2569"/>
		<updated>2023-12-21T10:03:54Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&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 de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 3 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteind une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, et le troisième processus ne fait rien pour notre démonstration. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme détaillé de  notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Carte écran schematic]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Carte fille ecran LCD]]&lt;br /&gt;
Après le point d'avancement avec les professeurs, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
[[Fichier:Partie inférieure carte écran .jpg|alt=Partie inférieure carte écran |vignette|Partie inférieure carte écran ]]&lt;br /&gt;
&lt;br /&gt;
==== Soudures et programmation : ====&lt;br /&gt;
[[Fichier:Carte écran.jpg|alt=Carte écran|gauche|vignette|Carte écran]]&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
[[Fichier:Blink carte fille.mp4|vignette|Blink carte fille|centré]]&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;br /&gt;
&lt;br /&gt;
Nous avons ensuite soudé le reste des composants (potentiomètre et connecteurs).[[Fichier:Imgecran.png|vignette|L'écran ne se comporte pas comme prevu.|310x310px]]&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;
Apres avoir debugé la carte on voit que un des concteurs de l'ecran n'etait pas relié a la masse. apres avoir corigé, lecran est alimenté correctement&lt;br /&gt;
&lt;br /&gt;
[[Fichier:WhatsApp Image 2023-12-12 at 16.09.54.jpg|vignette|Ecran alumé]]&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Partie_inf%C3%A9rieure_carte_%C3%A9cran_.jpg&amp;diff=2568</id>
		<title>Fichier:Partie inférieure carte écran .jpg</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Partie_inf%C3%A9rieure_carte_%C3%A9cran_.jpg&amp;diff=2568"/>
		<updated>2023-12-21T09:58:38Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Partie inférieure carte écran&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Carte_%C3%A9cran.jpg&amp;diff=2567</id>
		<title>Fichier:Carte écran.jpg</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Carte_%C3%A9cran.jpg&amp;diff=2567"/>
		<updated>2023-12-21T09:56:54Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Carte écran&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2566</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2566"/>
		<updated>2023-12-21T09:04:52Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&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 de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 3 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteind une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, et le troisième processus ne fait rien pour notre démonstration. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme détaillé de  notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Carte écran schematic]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Carte fille ecran LCD.pdf|alt=Carte fille ecran LCD|gauche|vignette|Carte fille ecran LCD]]&lt;br /&gt;
Après le point d'avancement avec les professeurs, nous nous sommes aperçus que nous n'avions pas correctement effectué le pinout de l'Atmega328p et que les ports MOSI, MISO et CLK n'étaient pas aux bons endroits. Nous avons donc su adapter notre carte afin qu'elle puisse être programmée.&lt;br /&gt;
&lt;br /&gt;
Nous avons donc corrigé le schematic afin qu'il puisse illustré correctement le fonctionnement de la carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:PCB carte ecran final.png|alt=PCB carte ecran final|gauche|vignette|Routage final]]&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Routage initial]]&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
&lt;br /&gt;
Nous avons aussi du adapter notre routage pour qu'il corresponde avec notre carte une fois nos erreurs corrigées.&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;
==== Soudures et programmation : ====&lt;br /&gt;
&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
[[Fichier:Blink carte fille.mp4|gauche|vignette|Blink carte fille]]&lt;br /&gt;
Comme nous l'avons évoqué précedemment, les connexions de l'AVR ISP était finalement en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&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;
Nous avons soudée le reste des composants (potentiometre et conneteurs.&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Imgecran.png|vignette|L'écran ne se comporte pas comme prevu.|310x310px]]&lt;br /&gt;
L'ecran ne se comporte pas comme prevu en effet en essayant d'afficher hello world il y a un simple caractere qui s'affiche. (ici 0).&lt;br /&gt;
&lt;br /&gt;
Apres avoir debugé la carte on voit que un des concteurs de l'ecran n'etait pas relié a la masse. apres avoir corigé, lecran est alimenté correctement&lt;br /&gt;
&lt;br /&gt;
[[Fichier:WhatsApp Image 2023-12-12 at 16.09.54.jpg|vignette|Ecran alumé]]&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:PCB_carte_ecran_final.png&amp;diff=2565</id>
		<title>Fichier:PCB carte ecran final.png</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:PCB_carte_ecran_final.png&amp;diff=2565"/>
		<updated>2023-12-21T09:02:46Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;PCB carte ecran final&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Carte_fille_ecran_LCD.pdf&amp;diff=2563</id>
		<title>Fichier:Carte fille ecran LCD.pdf</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=Fichier:Carte_fille_ecran_LCD.pdf&amp;diff=2563"/>
		<updated>2023-12-21T08:54:18Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Carte fille ecran LCD&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2446</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2446"/>
		<updated>2023-12-11T14:33:02Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&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 de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 3 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteind une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, et le troisième processus ne fait rien pour notre démonstration. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme détaillé de  notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Carte écran schematic]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Carté écran routage]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et tentatives de programmation : ====&lt;br /&gt;
&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivions pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
[[Fichier:Blink carte fille.mp4|gauche|vignette|Blink carte fille]]&lt;br /&gt;
Finalement, les connexions de l'AVR ISP était en cause, nous avions inversé SCK, MISO et MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2445</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2445"/>
		<updated>2023-12-11T14:31:37Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&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 de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 3 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteind une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, et le troisième processus ne fait rien pour notre démonstration. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme détaillé de  notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Carte écran schematic]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Carté écran routage]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et tentatives de programmation : ====&lt;br /&gt;
&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivons pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
[[Fichier:Blink carte fille.mp4|gauche|vignette|Blink carte fille]]&lt;br /&gt;
Finalement, les connexions de l'AVR ISP était en cause, nous avions inversé SCK, MISO, MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED. La carte fonctionne.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
	<entry>
		<id>https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2444</id>
		<title>SE4Binome2023-7</title>
		<link rel="alternate" type="text/html" href="https://projets-se.plil.fr/mediawiki/index.php?title=SE4Binome2023-7&amp;diff=2444"/>
		<updated>2023-12-11T14:30:42Z</updated>

		<summary type="html">&lt;p&gt;Apalifer : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= GIT =&lt;br /&gt;
https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer&lt;br /&gt;
&lt;br /&gt;
= Ordonnanceur = &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Matériel ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Fichier:Shield soudé et câbles HE10.jpg|vignette|Shield soudé et câbles HE10]]&lt;br /&gt;
Le premier objectif était de réaliser la partie matériel de notre projet.&lt;br /&gt;
&lt;br /&gt;
Un premier TP pratique nous a permis de réaliser différents composants qui allaient nous servir par la suite pour le bon fonctionnement de notre pico-ordinateur.&lt;br /&gt;
&lt;br /&gt;
Nous avons ainsi pu réaliser les composants suivant :&lt;br /&gt;
&lt;br /&gt;
* Réalisation des cables de liaison HE10 carte-mère/carte-fille avec des cables plats ruban 8 broches et des connecteurs HE10 femelles.&lt;br /&gt;
&lt;br /&gt;
* Réalisation du shield : soudure du Lecteur SD, des LEDs et résistances, et des ports HE10 males&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 de l'ordonnanceur ==&lt;br /&gt;
&lt;br /&gt;
Pour l'ordonnanceur, nous avons commencé par réaliser la fonction d'interruption qui se déclenche toutes les 20ms. Ensuite, nous avons créé 3 processus distincts afin de tester le bon fonctionnement de notre ordonnanceur. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void scheduler() {&lt;br /&gt;
 &lt;br /&gt;
  // Choisi la tâche suivante à exécuter en tournant en boucle&lt;br /&gt;
  currentTask = (currentTask + 1) % NUM_TASKS;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Le processus 2 allume et éteind une LED toutes les 500ms, le processus 0 réalise la même opération sur une LED différente toutes les 1000ms, et le troisième processus ne fait rien pour notre démonstration. &amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Définition des tâches&lt;br /&gt;
void task0() {&lt;br /&gt;
  // Code de la tâche 0&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTB, PB5);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(1000);&lt;br /&gt;
    Output_flip(&amp;amp;PORTB, PB5);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void task2() {&lt;br /&gt;
  //Code de la tâche 2&lt;br /&gt;
  Output_setHigh(&amp;amp;PORTD, PD7);&lt;br /&gt;
  while (1)&lt;br /&gt;
  {&lt;br /&gt;
    _delay_ms(500);&lt;br /&gt;
    Output_flip(&amp;amp;PORTD, PD7);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En implantant le programme sur la carte + shield, on constate que le programme fonctionne correctement, c'est-à-dire que chacune des deux LEDs clignotent à son rythme et les deux processus de gestion des LEDs fonctionnent simultanément.&lt;br /&gt;
[[Fichier:Blink.mp4|centré|vignette|Deux LEDs clignotent indépendamment]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Le programme détaillé de  notre ordonnanceur est disponible sur [https://archives.plil.fr/lwijsman/PICO_lwijsman_apalifer/tree/master/Ordonnanceur git].&lt;br /&gt;
&lt;br /&gt;
= Carte FPGA / VHDL =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Carte électronique numerique =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Carte fille écran LCD ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Référence écran : sparkfun ADM1602k-NSW-FBS&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Schematic : ====&lt;br /&gt;
[[Fichier:Schematic carte ecran.png|vignette|Carte écran schematic]]&lt;br /&gt;
La première étape de notre projet consistait à la réalisation du schematic sous KiCad de notre carte écran. Afin de réaliser le schéma du routage et pour que l'écran soit correctement connecté nous nous sommes référés à la documentation de l'écran afin de relier chacune des broches du connecteur aux labels correspondants. Vous trouverez ci-contre le schematic et les composants de la carte.&lt;br /&gt;
&lt;br /&gt;
Plus spécifiquement, cette carte possède :&lt;br /&gt;
&lt;br /&gt;
* un microcontroleur atmega328p&lt;br /&gt;
* un connecteur HE10 permettant de la relier à la carte mère&lt;br /&gt;
* un AVR ISP permettant la programmation de la carte&lt;br /&gt;
* des LEDs&lt;br /&gt;
* un connecteur 1x16 broches permettant la connexion avec l'écran&lt;br /&gt;
&lt;br /&gt;
Une fois le schematic réalisé et après vérification, nous avons pu commencer à effectuer le routage de notre carte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Routage : ====&lt;br /&gt;
&lt;br /&gt;
Pour le routage, nous avons également utilisé le logiciel KiCad. Vous trouverez ci-contre l'image correspondante à ce dernier.&lt;br /&gt;
[[Fichier:Routage PCB écran.png|vignette|Carté écran routage]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Soudures et tentatives de programmation : ====&lt;br /&gt;
&lt;br /&gt;
Après réception de la carte PCB, nous avons réalisé la soudure des composants sur la carte. Nous avons ainsi pu tenter de programmer la carte avec l'arduino en tant qu'ISP, mais nous avons une erreur. &lt;br /&gt;
Egalement, après un test en programmant directement la carte avec un programme simple en C et un makefile adapté, nous en sommes arrivés à la conclusion que notre carte était défaillante. &lt;br /&gt;
&lt;br /&gt;
Comme nous n'arrivons pas à programmer la carte, nous avons premièrement eu quelques doutes concernant la soudure du quartz, nous avons donc choisi de le remplacer mais cela n'a pas résolu le problème.&lt;br /&gt;
[[Fichier:Blink carte fille.mp4|gauche|vignette|Blink carte fille]]&lt;br /&gt;
Finalement, les connexions de l'AVR ISP était en cause, nous avions inversé SCK, MISO, MOSI. Nous avons donc réussi à corriger le problème directement en cablant sur la carte. Nous avons donc implémenté un programme pour tester le clignotement d'une LED.&lt;/div&gt;</summary>
		<author><name>Apalifer</name></author>
	</entry>
</feed>