Mini OS
Système minimal démontrant les bases d’un OS.
// Exemple de code pour le Mini OS
#include "xc.h"
// --- Configuration Bits (Example for PIC16/PIC18) ---
#pragma config WDTE = OFF // Disable Watchdog Timer
// Note: You may need to add other config bits depending on your exact PIC model
#define _XTAL_FREQ 4000000 // Define clock speed (4 MHz) for __delay_ms()
// --- Hardware Mapping ---
#define LED_TASK_A PORTBbits.RB0 // Indicator for Task A
#define LED_TASK_B PORTBbits.RB1 // Indicator for Task B
#define LED_OS_TICK PORTBbits.RB2 // Flashes to indicate the OS is changing tasks
// --- OS Structures ---
typedef enum {
TASK_A,
TASK_B
} TaskType;
TaskType current_task = TASK_A;
// --- Task Definitions ---
void execute_task_A() {
// Task A takes control of the CPU
LED_TASK_A = 1;
LED_TASK_B = 0;
// Simulate some workload being processed
__delay_ms(400);
}
void execute_task_B() {
// Task B takes control of the CPU
LED_TASK_A = 0;
LED_TASK_B = 1;
// Simulate some workload being processed
__delay_ms(400);
}
// --- OS Scheduler ---
void os_switch_task() {
// 1. Visual Indicator: The OS is actively switching tasks
LED_OS_TICK = 1;
__delay_ms(50); // Quick flash for visual feedback on the breadboard
LED_OS_TICK = 0;
// 2. Round-robin context switch logic
if (current_task == TASK_A) {
current_task = TASK_B;
} else {
current_task = TASK_A;
}
}
// --- Main System Entry ---
void main(void) {
// Initialize Hardware Ports
TRISB = 0x00; // Set all PORTB pins as outputs
PORTB = 0x00; // Ensure all LEDs start in the OFF state
// The "OS" Super-Loop
while(1) {
// 1. Dispatch the current task
if (current_task == TASK_A) {
execute_task_A();
}
else if (current_task == TASK_B) {
execute_task_B();
}
// 2. Task yields. Scheduler takes over to switch to the next one.
os_switch_task();
}
}
//////////////////////////////////////////////////////////////////////////////////////////////
Version ARINC 653
#include
// --- ARM Cortex-M MPU Hardware Registers ---
#define MPU_CTRL (*((volatile uint32_t*)0xE000ED94)) // MPU Control Register
#define MPU_RNR (*((volatile uint32_t*)0xE000ED98)) // Region Number Register
#define MPU_RBAR (*((volatile uint32_t*)0xE000ED9C)) // Region Base Address Register
#define MPU_RASR (*((volatile uint32_t*)0xE000EDA0)) // Region Attribute and Size Register
// --- Memory Map Definition ---
// Assume each task gets a strict 8 Kilobyte block of RAM
#define TASK_A_MEM_BASE 0x20002000
#define TASK_B_MEM_BASE 0x20004000
typedef enum { PARTITION_A, PARTITION_B } ActivePartition;
ActivePartition current_partition = PARTITION_A;
// --- Space Partitioning: The Hardware Wall ---
void load_mpu_for_task(ActivePartition task) {
// 1. Disable the MPU before configuring it
MPU_CTRL = 0;
// 2. Select MPU Region 1 (This is the slot we will use for our task RAM)
MPU_RNR = 1;
if (task == PARTITION_A) {
// Assign Task A's memory address
MPU_RBAR = TASK_A_MEM_BASE;
} else {
// Assign Task B's memory address
MPU_RBAR = TASK_B_MEM_BASE;
}
// 3. Set Attributes:
// - Enable the region
// - Set size to 8KB
// - Give Full Read/Write access ONLY to this specific 8KB block
// (A real OS would use bitwise operations here, using a magic hex value for brevity: 0x03080025)
MPU_RASR = 0x03080025;
// 4. Re-enable the MPU
// The hardware wall is now active. If the task tries to access address 0x20000000
// or 0x20006000, the CPU will immediately trigger a "MemManage Fault" (Hardware Crash).
MPU_CTRL = 1;
}
// --- Time Partitioning: The Unforgiving Clock ---
// This is the hardware timer interrupt (SysTick) that fires exactly every 10 milliseconds.
// The tasks CANNOT stop this from happening.
void SysTick_Handler(void) {
// 1. Stop the current task and save its CPU registers (Context Save)
// __asm volatile ("... save registers to stack ...");
// 2. Switch the active partition
if (current_partition == PARTITION_A) {
current_partition = PARTITION_B;
} else {
current_partition = PARTITION_A;
}
// 3. Reconfigure the physical memory walls for the new task
load_mpu_for_task(current_partition);
// 4. Load the new task's CPU registers and resume execution (Context Restore)
// __asm volatile ("... load registers from stack ...");
}
// --- Main Kernel Boot ---
int main(void) {
// Initialize standard hardware (Clocks, UART, etc.)
// Configure the SysTick hardware timer to fire every 10ms
// This enforces our strict Time Slicing
// SystemCoreClock / 100 = 10ms interrupts
// SysTick_Config(SystemCoreClock / 100);
// Load Task A's memory walls to start
load_mpu_for_task(PARTITION_A);
// Jump to the first task
// execute_task_A();
while(1) {
// The main OS thread sleeps here.
// All the work is driven by the SysTick hardware interrupt violently swapping tasks.
}
}