SE4Binome2024-3

De projets-se.plil.fr
Aller à la navigation Aller à la recherche

Description

L'objectif de ce projet est de réaliser un pico ordinateur. Nous allons traiter le développement de la carte mère, un shield arduino ainsi que la programmation d'un ordonnanceur.

Notre carte mère sera alimenté via une alimentation secteur en 5v et le code sera implanté par USB.

Choix technologique

Pour alimenter les cartes filles, nous avons fait le choix de rendre disponible à la fois le 3v3 et le 5v. Pour ce faire nous allons utiliser des connecteurs HE -0 10 pins et non 8 pins dont voici les références :

-

Réalisation d'un shield arduino

Schématique

Schematique shield CART DETREZ.pdf

Routage

Routage shield CART DETREZ.png

PINOUT

LED1 PC0
LED2 PC3
LED3 PD1
LED4 PD4
LED5 PD7

Brasage du shield

shield nu

Shield nu CART DETREZ 2.jpg

shield fini

Shield fini CART DETREZ.jpg

Test du shield

Affichage 7 segments DETREZ CART.jpg

Réalisation carte mère

Schématique

Routage

Programmation ordonnanceur

Initialisation de la pile

void init_pile(int N){
    uint16_t tempSP = SP;
    SP = task[N].stackPointer;
    uint16_t adresse=(uint16_t)task[N].addressFunction;
    asm volatile("push %0" : : "r" (adresse & 0x00ff) );
    asm volatile("push %0" : : "r" ((adresse & 0xff00)>>8) );
    SAVE_REGISTERS();
    task[N].stackPointer = SP;
    SP = tempSP;
}

La fonction init_pile() sert à charger un processus dans la pile. Cette fonction est appelée dans une boucle au début du main pour initialiser tous les processus.

Interruption de l'ordonnanceur

L'ordonnanceur est appelé à un interval de temps régulier grâce à des interruptions du Timer1.

Avant de passer d'une tâche à une autre (mode Round Robin) il faut d'abord effectuer quelques opérations sur la mémoire du micro-processeur.

ISR(TIMER1_COMPA_vect, ISR_NAKED){    // Procédure d'interruption
    /* Sauvegarde du contexte de la tâche interrompue */
    SAVE_REGISTERS();
    task[currentTask].stackPointer = SP;
    /* Appel à l'ordonnanceur */
    scheduler();
    /* Récupération du contexte de la tâche ré-activée */
    SP = task[currentTask].stackPointer;
    RESTORE_REGISTERS();
    asm volatile ( "reti" );
}

TODO : explication des interruptions (pourquoi en NAKED, chaque fonctions, le reti ...)

Structure d'une tâche

enum States{
    AWAKE,
    IDLE
};

enum IDLE_TYPE{
    IDLE_TYPE_DELAY,
    IDLE_TYPE_STABLE
};

typedef union {
  int sleeping_time;
} Time;

typedef struct {
  enum IDLE_TYPE type;
  Time time;
} Etat ;

typedef struct{
    uint16_t stackPointer; // stack pointer, défini le début du process
    void (*addressFunction)(void); // adresse de l'instruction en cours
    enum States state; // état de la fonction (Awake ou Idle)
    Etat etat;
}process;

TODO : explication de Etat qui est utile pour la mise en veille des processus

Code de l'ordonnanceur

void scheduler(){

// décrémentation de l'attente de toutes les tâches en IDLE
for(int i=0;i<NB_TASKS;i++){
    if(task[i].state==IDLE && (task[i].etat.type==IDLE_TYPE_DELAY)){
        task[i].etat.time.sleeping_time -= PERIODE;
        if(task[i].etat.time.sleeping_time <= 0){
            task[i].etat.time.sleeping_time = 0;
            task[i].state = AWAKE;
        }
    }
}
do{
  currentTask ++;
  if(currentTask >= NB_TASKS) currentTask = 0; // ordonnanceur en mode Round Robin
  }while(task[currentTask].state == IDLE);
}

TODO : explication de l'ordonnanceur : Round robin, explication du IDLE et de l'intérêt de ne pas faire tourner des tâches qui sont en veille

Fonction wait

void wait(int time_ms){
    task[currentTask].state = IDLE;
    task[currentTask].etat.type=IDLE_TYPE_DELAY;
    task[currentTask].etat.time.sleeping_time = time_ms;
    TCNT1 = 0;
    TIMER1_COMPA_vect();
}

Permet d'endormir un processus pendant un temps donné en ms.

Exemple de tâches

void USART_Init(unsigned int ubrr)
{
/*Set baud rate */
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
/*Enable receiver and transmitter */
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
/* Set frame format: 8data, 2stop bit */
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
void LED_init(){
    DDRC |= (1<<LED1) | (1<<LED2);
    DDRD |= (1<<LED3) | (1<<LED4) | (1<<LED5);
    PORTC |= (1<<LED1)|(1<<LED2);
    PORTD |= (1<<LED3)|(1<<LED4)|(1<<LED5);
}

void LED1_blink(){
    while(1){
        PORTC ^= (1<<LED1);
        _delay_ms(1000);
    }
}

void LED2_blink(){
    while(1){
        PORTC ^= (1<<LED2);
        wait(100);
    }
}


void Serial_Message(){
    unsigned char data;
    while(1){
         data = USART_Receive();
        USART_Transmit(data);
    }
}

void USART_Transmit(unsigned char data)
{
/* Wait for empty transmit buffer */
while (!(UCSR0A & (1<<UDRE0)))
;
/* Put data into buffer, sends the data */
UDR0 = data;
}

unsigned char USART_Receive(void)
{
/* Wait for data to be received */
while (!(UCSR0A & (1<<RXC0)))
;
/* Get and return received data from buffer */
return UDR0;
}
void spi_activer(void){                              // Activer le périphérique
    PORTD &= ~(1<<SPI_SS);                            // Ligne SS à l'état bas
}

void spi_desactiver(void){                           // Désactiver le périphérique
    PORTD |= (1<<SPI_SS);                             // Ligne SS à l'état haut
}

uint8_t spi_echange(uint8_t envoi){                  // Communication sur le bus SPI
    SPDR = envoi;                                        // Octet a envoyer
    while(!(SPSR & (1<<SPIF)));                          // Attente fin envoi (drapeau SPIF du statut)
    return SPDR;                                         // Octet reçu
}

void seven_seg(){
    while(1){
    spi_activer();
    spi_echange(0x01);
    spi_desactiver();
    }
}

Exemple d'utilisation

Clignotement de 5 Leds asynchrones

Affichage clavier avec minicom

Bilan de puissance

Bilan de puissance (VCC = 3.3V)
Composant Courant Puissance
74LVC125 40 uA 0.2mW
Carte SD 100 mA 330 mW
TOTAL 100,04 mA 330.2 mW
Bilan de puissance (Vcc = 5V)
Composant Courant Puissance
AtMega328p 14mA 70mW
ATMega8U2 21mA 105mW
5xLED 5*5mA 5*25 mW
TOTAL 60mA 300 mW
Bilan de puissance général du groupe
CARTE PUISSANCE (maximale)
Mère 0,63W
Clavier 0,17W
Réseau 0,15W
Ecran 1,735W
TOTAL 2,685W

Liens

Lien du git : https://gitea.plil.fr/vdetrez/SE4_PICO_DETREZ_CART