238 lines
7.6 KiB
C
238 lines
7.6 KiB
C
// os.c
|
|
// Runs on LM4F120/TM4C123/MSP432
|
|
// Lab 2 starter file.
|
|
// Daniel Valvano
|
|
// February 20, 2016
|
|
|
|
#include <stdint.h>
|
|
#include "os.h"
|
|
#include "../inc/CortexM.h"
|
|
#include "../inc/BSP.h"
|
|
|
|
// function definitions in osasm.s
|
|
void StartOS(void);
|
|
|
|
periodicType periodic[2];
|
|
tcbType tcbs[4];
|
|
tcbType *RunPt;
|
|
int32_t Stacks[4][STACKSIZE];
|
|
|
|
|
|
// ******** OS_Init ************
|
|
// Initialize operating system, disable interrupts
|
|
// Initialize OS controlled I/O: systick, bus clock as fast as possible
|
|
// Initialize OS global variables
|
|
// Inputs: none
|
|
// Outputs: none
|
|
void OS_Init(void){
|
|
DisableInterrupts();
|
|
BSP_Clock_InitFastest();// set processor clock to fastest speed
|
|
// initialize any global variables as needed
|
|
}
|
|
|
|
void SetInitialStack(int i){
|
|
tcbs[i].sp = &Stacks[i][STACKSIZE - 16];
|
|
|
|
Stacks[i][STACKSIZE-1] = 0x01000000; // Thumb bit
|
|
//Stacks[i][STACKSIZE-2] is reserved for PC
|
|
//and is initialized with start address of task
|
|
Stacks[i][STACKSIZE-3] = 0x14141414; // R14 = LR
|
|
Stacks[i][STACKSIZE-4] = 0x12121212; // R12
|
|
Stacks[i][STACKSIZE-5] = 0x03030303; // R3
|
|
Stacks[i][STACKSIZE-6] = 0x02020202; // R2
|
|
Stacks[i][STACKSIZE-7] = 0x01010101; // R1
|
|
Stacks[i][STACKSIZE-8] = 0x00000000; // R0
|
|
Stacks[i][STACKSIZE-9] = 0x11111111; // R11
|
|
Stacks[i][STACKSIZE-10] = 0x10101010; // R10
|
|
Stacks[i][STACKSIZE-11] = 0x09090909; // R9
|
|
Stacks[i][STACKSIZE-12] = 0x08080808; // R8
|
|
Stacks[i][STACKSIZE-13] = 0x07070707; // R7
|
|
Stacks[i][STACKSIZE-14] = 0x06060606; // R6
|
|
Stacks[i][STACKSIZE-15] = 0x05050505; // R5
|
|
Stacks[i][STACKSIZE-16] = 0x04040404; // R4
|
|
}
|
|
|
|
//******** OS_AddThreads ***************
|
|
// Add four main threads to the scheduler
|
|
// Inputs: function pointers to four void/void main threads
|
|
// Outputs: 1 if successful, 0 if this thread can not be added
|
|
// This function will only be called once, after OS_Init and before OS_Launch
|
|
int OS_AddThreads(void(*thread0)(void),
|
|
void(*thread1)(void),
|
|
void(*thread2)(void),
|
|
void(*thread3)(void)){
|
|
// initialize TCB circular list
|
|
// initialize RunPt
|
|
// initialize four stacks, including initial PC
|
|
uint32_t status = StartCritical();
|
|
tcbs[0].next = &tcbs[1];
|
|
tcbs[1].next = &tcbs[2];
|
|
tcbs[2].next = &tcbs[3];
|
|
tcbs[3].next = &tcbs[0];
|
|
|
|
SetInitialStack(0); Stacks[0][STACKSIZE-2] = (int32_t)(thread0);
|
|
SetInitialStack(1); Stacks[1][STACKSIZE-2] = (int32_t)(thread1);
|
|
SetInitialStack(2); Stacks[2][STACKSIZE-2] = (int32_t)(thread2);
|
|
SetInitialStack(3); Stacks[3][STACKSIZE-2] = (int32_t)(thread3);
|
|
|
|
RunPt = &tcbs[0];
|
|
EndCritical(status);
|
|
return 1; // successful
|
|
}
|
|
|
|
//******** OS_AddThreads3 ***************
|
|
// add three foregound threads to the scheduler
|
|
// This is needed during debugging and not part of final solution
|
|
// Inputs: three pointers to a void/void foreground tasks
|
|
// Outputs: 1 if successful, 0 if this thread can not be added
|
|
int OS_AddThreads3(void(*task0)(void),
|
|
void(*task1)(void),
|
|
void(*task2)(void)){
|
|
// initialize TCB circular list (same as RTOS project)
|
|
// initialize RunPt
|
|
// initialize four stacks, including initial PC
|
|
uint32_t status = StartCritical();
|
|
tcbs[0].next = &tcbs[1];
|
|
tcbs[1].next = &tcbs[2];
|
|
tcbs[2].next = &tcbs[0];
|
|
|
|
SetInitialStack(0); Stacks[0][STACKSIZE-2] = (int32_t)(task0);
|
|
SetInitialStack(1); Stacks[1][STACKSIZE-2] = (int32_t)(task1);
|
|
SetInitialStack(2); Stacks[2][STACKSIZE-2] = (int32_t)(task2);
|
|
|
|
RunPt = &tcbs[0];
|
|
EndCritical(status);
|
|
return 1; // successful
|
|
}
|
|
|
|
//******** OS_AddPeriodicEventThreads ***************
|
|
// Add two background periodic event threads
|
|
// Typically this function receives the highest priority
|
|
// Inputs: pointers to a void/void event thread function2
|
|
// periods given in units of OS_Launch (Lab 2 this will be msec)
|
|
// Outputs: 1 if successful, 0 if this thread cannot be added
|
|
// It is assumed that the event threads will run to completion and return
|
|
// It is assumed the time to run these event threads is short compared to 1 msec
|
|
// These threads cannot spin, block, loop, sleep, or kill
|
|
// These threads can call OS_Signal
|
|
int OS_AddPeriodicEventThreads(void(*thread1)(void), uint32_t period1,
|
|
void(*thread2)(void), uint32_t period2){ //TODO
|
|
int32_t status;
|
|
status = StartCritical();
|
|
periodic[0].period = period1;
|
|
periodic[0].task = thread1;
|
|
periodic[1].period = period2;
|
|
periodic[1].task = thread2;
|
|
EndCritical(status);
|
|
return 1; // successful
|
|
}
|
|
|
|
//******** OS_Launch ***************
|
|
// Start the scheduler, enable interrupts
|
|
// Inputs: number of clock cycles for each time slice
|
|
// Outputs: none (does not return)
|
|
// Errors: theTimeSlice must be less than 16,777,216
|
|
void OS_Launch(uint32_t theTimeSlice){
|
|
STCTRL = 0; // disable SysTick during setup
|
|
STCURRENT = 0; // any write to current clears it
|
|
SYSPRI3 =(SYSPRI3&0x00FFFFFF)|0xE0000000; // priority 7
|
|
STRELOAD = theTimeSlice - 1; // reload value
|
|
STCTRL = 0x00000007; // enable, core clock and interrupt arm
|
|
StartOS(); // start on the first task
|
|
}
|
|
static uint32_t timer = 0;
|
|
// runs every ms
|
|
void Scheduler(void){ // every time slice
|
|
// run any periodic event threads if needed
|
|
// implement round robin scheduler, update RunPt
|
|
|
|
for (int i = 0; i < 2; ++i) {
|
|
if ((timer % periodic[i].period) == 0) {
|
|
periodic[i].task();
|
|
}
|
|
}
|
|
++timer;
|
|
|
|
RunPt = RunPt->next; // Round Robin
|
|
}
|
|
|
|
// ******** OS_InitSemaphore ************
|
|
// Initialize counting semaphore
|
|
// Inputs: pointer to a semaphore
|
|
// initial value of semaphore
|
|
// Outputs: none
|
|
void OS_InitSemaphore(int32_t *semaPt, int32_t value){
|
|
*semaPt = value;
|
|
}
|
|
|
|
// ******** OS_Wait ************
|
|
// Decrement semaphore
|
|
// Lab2 spinlock (does not suspend while spinning)
|
|
// Lab3 block if less than zero
|
|
// Inputs: pointer to a counting semaphore
|
|
// Outputs: none
|
|
void OS_Wait(int32_t *semaPt){
|
|
uint32_t status = StartCritical();
|
|
while (*semaPt <= 0) {
|
|
EndCritical(status);
|
|
status = StartCritical();
|
|
}
|
|
--(*semaPt);
|
|
EndCritical(status);
|
|
}
|
|
|
|
// ******** OS_Signal ************
|
|
// Increment semaphore
|
|
// Lab2 spinlock
|
|
// Lab3 wakeup blocked thread if appropriate
|
|
// Inputs: pointer to a counting semaphore
|
|
// Outputs: none
|
|
void OS_Signal(int32_t *semaPt){
|
|
uint32_t status = StartCritical();
|
|
++(*semaPt);
|
|
EndCritical(status);
|
|
}
|
|
|
|
|
|
|
|
|
|
// ******** OS_MailBox_Init ************
|
|
// Initialize communication channel
|
|
// Producer is an event thread, consumer is a main thread
|
|
// Inputs: none
|
|
// Outputs: none
|
|
uint32_t MailBox;
|
|
int32_t MailBox_Send;
|
|
int32_t MailBox_Ack;
|
|
void OS_MailBox_Init(void){
|
|
// include data field and semaphore
|
|
MailBox = 0;
|
|
OS_InitSemaphore(&MailBox_Send, 0);
|
|
OS_InitSemaphore(&MailBox_Ack, 0);
|
|
}
|
|
|
|
// ******** OS_MailBox_Send ************
|
|
// Enter data into the MailBox, do not spin/block if full
|
|
// Use semaphore to synchronize with OS_MailBox_Recv
|
|
// Inputs: data to be sent
|
|
// Outputs: none
|
|
// Errors: data lost if MailBox already has data
|
|
void OS_MailBox_Send(uint32_t data){
|
|
MailBox = data; // Overwrite data (may lose old data)
|
|
OS_Signal(&MailBox_Send); // Signal data availability
|
|
}
|
|
|
|
// ******** OS_MailBox_Recv ************
|
|
// retreive mail from the MailBox
|
|
// Use semaphore to synchronize with OS_MailBox_Send
|
|
// Lab 2 spin on semaphore if mailbox empty
|
|
// Lab 3 block on semaphore if mailbox empty
|
|
// Inputs: none
|
|
// Outputs: data retreived
|
|
// Errors: none
|
|
uint32_t OS_MailBox_Recv(void){
|
|
OS_Wait(&MailBox_Send);
|
|
int32_t data = MailBox; // read mail
|
|
return data;
|
|
}
|