SE4Binome2025-2
Aller à la navigation
Aller à la recherche
Objectif
L'objectif du projet est de concevoir un pico-ordinateur complet, intégrant :
- Une carte mère basée sue le microcontrôleur AT90USB1286
Une partie logicielle permettant l'éxecution de de commandes telles que ls, cp ou mv
Shield Arduino
Une première étape du projet a consisté à développer un shield pour Aduino uno, servant de plateforme de test et de développement pour les cartes filles SPI.
Fonctionalités:
- Connexion de 5 périphériques SPI via des cartes filles.
- Gestion des signaux Reset et Interruption.
- Ajout d'une mémoire externe carte micro-SD via un connecteur Molex 10431.
- Adaptation des niveaux logiques (5V a 3,3V) grâce à la puce 74LV125.
Ce shield joue le rôle de plateforme de développement temporaire, en attendant la carte mère du pico-ordinateur.
Schématique et routage
Objectif
Carte mère
Schématique
Firmware — RTOS (version restructurée et en français)
1. Vue d’ensemble du système
Le firmware implémente un petit RTOS coopératif optimisé en mémoire pour ATmega (ex. ATmega328P). Principales caractéristiques :
- Ordonnanceur round-robin simple.
- Table des tâches statique (pas d’allocation dynamique).
- Gestion des sections critiques imbriquées.
- Timer système à 100 Hz pour la gestion des ticks et du sommeil.
2. Arborescence (extrait)
firmware/ ├─ kernel/ │ ├─ kernel.h │ ├─ kernel.c │ ├─ scheduler.h │ ├─ scheduler.c │ ├─ task.h │ └─ task.c ├─ config.h └─ main.c
3. Paramètres de configuration
#define MAX_TASKS 4 // nombre max de tâches
#define STACK_SIZE 96 // octets par pile de tâche
#define TICK_FREQUENCY 100 // Hz — fréquence du tick système
#define TASK_NAME_LEN 8
4. Structure de contrôle de tâche (TCB)
typedef enum {
TASK_INVALID = 0,
TASK_READY,
TASK_RUNNING,
TASK_SLEEPING
} task_state_t;
typedef struct {
void (*function)(void *);
void *arg;
uint8_t *stack_base;
task_state_t state;
uint16_t sleep_ticks;
uint8_t priority;
char name[TASK_NAME_LEN];
} task_t;
5. Gestion des sections critiques (imbriquées)
#include <avr/interrupt.h>
static volatile uint8_t critical_nesting = 0;
static inline void enter_critical(void) {
cli();
critical_nesting++;
}
static inline void leave_critical(void) {
if (critical_nesting > 0) {
critical_nesting--;
if (critical_nesting == 0) sei();
}
}
6. Création de tâche
int8_t task_create(const char *name, void (*function)(void *), void *arg,
uint8_t priority, uint8_t *stack_buffer)
{
for (uint8_t i = 0; i < MAX_TASKS; i++) {
if (task_table[i].function == NULL) {
task_table[i].function = function;
task_table[i].arg = arg;
task_table[i].stack_base = stack_buffer;
task_table[i].state = TASK_READY;
task_table[i].priority = priority;
strncpy(task_table[i].name, name, TASK_NAME_LEN);
return i;
}
}
return -1;
}
7. Ordonnanceur (round-robin)
static uint8_t current_task_id = 0;
static inline uint8_t is_task_valid(uint8_t id) {
return (id < MAX_TASKS) &&
(task_table[id].function != NULL) &&
(task_table[id].state == TASK_READY);
}
static uint8_t get_next_task(void) {
uint8_t next = (current_task_id + 1) % MAX_TASKS;
for (uint8_t i = 0; i < MAX_TASKS; i++) {
if (is_task_valid(next)) return next;
next = (next + 1) % MAX_TASKS;
}
return current_task_id;
}
void scheduler_run(void) {
enter_critical();
if (is_task_valid(current_task_id)) {
task_table[current_task_id].state = TASK_RUNNING;
leave_critical();
task_table[current_task_id].function(task_table[current_task_id].arg);
enter_critical();
if (task_table[current_task_id].state == TASK_RUNNING)
task_table[current_task_id].state = TASK_READY;
}
current_task_id = get_next_task();
leave_critical();
}
8. Mécanismes de sommeil et tick système
void timer1_init_100hz(void) {
TCCR1A = 0;
TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10);
OCR1A = 2499;
TIMSK1 |= (1 << OCIE1A);
}
ISR(TIMER1_COMPA_vect) {
extern volatile uint32_t system_ticks;
system_ticks++;
for (uint8_t i = 0; i < MAX_TASKS; i++) {
if (task_table[i].state == TASK_SLEEPING && task_table[i].sleep_ticks > 0) {
task_table[i].sleep_ticks--;
if (task_table[i].sleep_ticks == 0)
task_table[i].state = TASK_READY;
}
}
}
void task_sleep(uint16_t ticks) {
if (ticks == 0) ticks = 1;
enter_critical();
task_table[current_task_id].sleep_ticks = ticks;
task_table[current_task_id].state = TASK_SLEEPING;
leave_critical();
scheduler_run();
}
9. Initialisation du système
- Mise à zéro des structures de données.
- Initialisation du timer à 100 Hz.
- Création de la tâche d’« idle ».
- Activation des interruptions globales.
- Lancement de la boucle principale qui exécute `scheduler_run()`.
10. Gestion d’erreurs
- Vérification de la validité des pointeurs de fonctions.
- Conversion des durées nulles (`sleep(0)`) en `sleep(1)`.
- Gestion des appels imbriqués de sections critiques.
- Fallback automatique sur la tâche idle si aucune tâche prête.
11. Estimations mémoire
- Piles : 4 × 96 = 384 octets
- TCB : 4 × 28 = 112 octets (approx.)
- Variables globales : ~20 octets
- **Total estimé :** ~516 octets
12. Intégration du build system
MCU = atmega328p
F_CPU = 16000000UL
CFLAGS = -mmcu=$(MCU) -DF_CPU=$(F_CPU) -Os -Wall -std=c99