SE4Binome2025-2

De projets-se.plil.fr
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

Schema shield arduino.jpg

Objectif

Schema shield arduino


Routage shield arduino


Carte mère

Schématique

Schéma carte mère du pico ordinateur



Firmware: RTOS

System Architecture Overview

The firmware implements a cooperative real-time operating system (RTOS) for ATmega328p microcontrollers, featuring a memory-optimized kernel with round-robin scheduling capabilities.

Component Hierarchy

firmware/ ├── kernel/ │ ├── kernel.[ch] - Core kernel management │ ├── scheduler.[ch] - Task scheduler implementation │ ├── task.[ch] - Task control block system │ └── config.h - Resource configuration └── main.c - Application layer

Core Kernel Mechanisms
Task Management System

The kernel implements a static task control block (TCB) architecture:

typedef struct task_control_block {

   void (*function)(void*);    // Task entry point
   void* arg;                  // Task parameters
   uint8_t* stack_base;        // Stack memory (96 bytes)
   task_state_t state;         // Current task state
   uint16_t sleep_ticks;       // Sleep countdown
   uint8_t priority;          // Execution priority (0-3)
   char name[TASK_NAME_LENGTH]; // Task identifier

} task_t;

Task State Transitions

The system implements a finite state machine for task management:

$$\text{TASK\_READY} \rightleftharpoons \text{TASK\_RUNNING} \rightarrow \text{TASK\_SLEEPING} \rightarrow \text{TASK\_READY}$$

Task Creation Protocol

int8_t task_create(const char* name, void (*function)(void*),

                  void* arg, uint8_t priority, uint8_t* stack_buffer)

    • Creation Constraints:**
 * Maximum task count: $MAX\_TASKS = 4$
 * Stack size: $STACK\_SIZE = 96$ bytes
 * Priority levels: $\{PRIORITY\_IDLE, PRIORITY\_LOW, PRIORITY\_MEDIUM, PRIORITY\_HIGH\}$
Scheduling Algorithm
Round-Robin Implementation

The scheduler employs a circular search algorithm to find the next executable task:

static uint8_t get_next_task(void) {

   uint8_t next_task = (current_task_id + 1) % MAX_TASKS;
   for (uint8_t i = 0; i < MAX_TASKS; i++) {
       if (is_task_valid(next_task) && 
           task_table[next_task].state == TASK_READY) {
           return next_task;
       }
       next_task = (next_task + 1) % MAX_TASKS;
   }
   return current_task_id;

}

Execution Flow

The main scheduler loop follows this sequence:

 - Enter critical section (disable interrupts)
 - Execute current task function
 - Calculate next task ID using round-robin
 - Leave critical section (enable interrupts)
 - Apply 1ms CPU delay to prevent overload
Memory Management
Resource Allocation

The system employs static memory allocation for predictable resource usage:

$$\begin{align*} \text{Total RAM for stacks} &= MAX\_TASKS \times STACK\_SIZE = 4 \times 96 = 384 \text{ bytes} \\ \text{TCB memory footprint} &= MAX\_TASKS \times sizeof(task\_t) \approx 112 \text{ bytes} \\ \text{Global variables} &\approx 20 \text{ bytes} \\ \text{Total estimated usage} &\approx 516 \text{ bytes} \end{align*}$$

Configuration Parameters

  1. define MAX_TASKS 4 // Maximum concurrent tasks
  2. define STACK_SIZE 96 // Bytes per task stack
  3. define TICK_FREQUENCY 100 // Hz - scheduler frequency
  4. define TASK_NAME_LENGTH 8 // Maximum task name characters

Interrupt and Critical Section Management
Atomic Operation Protection

The kernel implements nested critical sections to protect shared resources:

void enter_critical_section(void) {

   cli();                    // Disable interrupts
   critical_nesting++;       // Track nesting depth

}

void leave_critical_section(void) {

   if (critical_nesting > 0) critical_nesting--;
   if (critical_nesting == 0) sei();  // Re-enable interrupts

}

Timer Interrupt Configuration

The system timer generates 100Hz interrupts for tick management:

$$OCR1A = \frac{F\_CPU}{Prescaler \times Frequency} - 1 = \frac{16,000,000}{64 \times 100} - 1 = 2499$$

// Timer1 configuration for 100Hz TCCR1A = 0; TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10); OCR1A = 2499; TIMSK1 |= (1 << OCIE1A);

Sleep and Timing Mechanisms
Tick-Based Sleep System

Tasks can suspend execution for precise durations using system ticks:

$$\text{sleep\_ticks} = \left\lceil \frac{\text{milliseconds}}{10} \right\rceil$$

void task_sleep(uint16_t ticks) {

   enter_critical_section();
   task_table[current_task_id].sleep_ticks = ticks;
   task_table[current_task_id].state = TASK_SLEEPING;
   leave_critical_section();
   schedule();

}

Tick Update Algorithm

The interrupt service routine manages sleeping tasks:

ISR(TIMER1_COMPA_vect) {

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

}

System Initialization Sequence
Boot Process
 - **Memory Zeroing**: Clear task table and global variables
 - **Timer Configuration**: Setup 100Hz interrupt timer
 - **Idle Task Creation**: Initialize fallback task with lowest priority
 - **Interrupt Enable**: Start scheduler tick generation
 - **Task Validation**: Mark all created tasks as READY state
Error Handling and Robustness
Boundary Condition Management
 * **Task Validation**: All task executions verify function pointer validity
 * **Sleep Sanitization**: Zero-tick sleep requests default to 1 tick
 * **Circular Search**: Scheduler handles empty task tables gracefully
 * **Nesting Safety**: Critical sections properly handle nested calls
Recovery Mechanisms

static uint8_t is_task_valid(uint8_t task_id) {

   return (task_id < MAX_TASKS && task_table[task_id].function != NULL);

}

Performance Characteristics
Computational Complexity

Algorithm Complexity Analysis ^**Operation** ^**Time Complexity** ^**Space Complexity** ^ |Task Creation |$O(n)$ |$O(1)$ | |Task Scheduling |$O(n)$ |$O(1)$ | |Sleep Update |$O(n)$ |$O(1)$ | |Context Switch |$O(1)$ |$O(1)$ |

Memory Efficiency

The system achieves high memory efficiency through:

 * Static allocation eliminating heap fragmentation
 * Fixed-size arrays for predictable memory usage
 * Stack sharing between kernel and application
 * Minimal TCB overhead (28 bytes per task)
Build System Integration
Compilation Configuration

MCU = atmega328p F_CPU = 16000000UL CFLAGS = -mmcu=$(MCU) -DF_CPU=$(F_CPU) -Os -Wall -std=c99

Memory Section Allocation

$$\begin{align*} \text{Program Memory} &= \text{.text} + \text{.data} \\ \text{RAM Usage} &= \text{.data} + \text{.bss} + \text{Stack} \end{align*}$$