« SE4Binome2025-2 » : différence entre les versions
Aucun résumé des modifications |
|||
| Ligne 37 : | Ligne 37 : | ||
= Firmware: RTOS = | = Firmware: RTOS = | ||
====== System Architecture Overview ====== | |||
The firmware implements a cooperative real-time operating system (RTOS) for | 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 ===== | |||
<code> | |||
firmware/ | 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 | |||
</code> | |||
====== Core Kernel Mechanisms ====== | |||
===== Task Management System ===== | |||
The kernel implements a static task control block (TCB) architecture: | The kernel implements a static task control block (TCB) architecture: | ||
< | <code objc> | ||
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; | |||
</code> | |||
===== Task State Transitions ===== | |||
The system implements a finite state machine for task management: | 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 ===== | |||
< | <code objc> | ||
int8_t task_create(const char* name, void (*function)(void*), | |||
void* arg, uint8_t priority, uint8_t* stack_buffer) | |||
</code> | |||
**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: | The scheduler employs a circular search algorithm to find the next executable task: | ||
< | <code objc> | ||
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; | |||
} | |||
</code> | |||
===== Execution Flow ===== | |||
The main scheduler loop follows this sequence: | 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: | 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} \\ | |||
TCB memory footprint = | \text{Total estimated usage} &\approx 516 \text{ bytes} | ||
\end{align*}$$ | |||
Global variables | |||
===== Configuration Parameters ===== | |||
<code objc> | |||
< | #define MAX_TASKS 4 // Maximum concurrent tasks | ||
#define STACK_SIZE 96 // Bytes per task stack | |||
#define TICK_FREQUENCY 100 // Hz - scheduler frequency | |||
#define TASK_NAME_LENGTH 8 // Maximum task name characters | |||
</code> | |||
====== Interrupt and Critical Section Management ====== | |||
===== Atomic Operation Protection ===== | |||
The kernel implements nested critical sections to protect shared resources: | The kernel implements nested critical sections to protect shared resources: | ||
<code objc> | |||
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 | |||
} | |||
</code> | |||
===== Timer Interrupt Configuration ===== | |||
The system timer generates 100Hz interrupts for tick management: | 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$$ | |||
<code objc> | |||
// Timer1 configuration for 100Hz | |||
TCCR1A = 0; | TCCR1A = 0; | ||
TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10); | |||
OCR1A = 2499; | |||
TIMSK1 |= (1 << OCIE1A); | |||
</code> | |||
| | |||
< | |||
</ | |||
====== 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$$ | |||
{ | <code objc> | ||
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(); | |||
} | |||
</code> | |||
</ | |||
===== Tick Update Algorithm ===== | |||
The interrupt service routine manages sleeping tasks: | The interrupt service routine manages sleeping tasks: | ||
< | <code objc> | ||
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; | |||
} | |||
} | |||
} | |||
} | |||
</code> | |||
====== 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 ===== | |||
<code objc> | |||
static uint8_t is_task_valid(uint8_t task_id) { | |||
return (task_id < MAX_TASKS && task_table[task_id].function != NULL); | |||
} | |||
</code> | |||
====== 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 ===== | |||
<code make> | |||
MCU = atmega328p | |||
F_CPU = 16000000UL | |||
CFLAGS = -mmcu=$(MCU) -DF_CPU=$(F_CPU) -Os -Wall -std=c99 | |||
</code> | |||
===== Memory Section Allocation ===== | |||
$$\begin{align*} | |||
Program Memory = .text + .data | \text{Program Memory} &= \text{.text} + \text{.data} \\ | ||
RAM Usage = .data + .bss + Stack | \text{RAM Usage} &= \text{.data} + \text{.bss} + \text{Stack} | ||
\end{align*}$$ | |||
Version du 11 novembre 2025 à 13:56
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
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
- define MAX_TASKS 4 // Maximum concurrent tasks
- define STACK_SIZE 96 // Bytes per task stack
- define TICK_FREQUENCY 100 // Hz - scheduler frequency
- 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*}$$