// os.c // Runs on LM4F120/TM4C123/MSP432 // A priority/blocking real-time operating system // Lab 4 starter file. // Daniel Valvano // March 25, 2016 // Hint: Copy solutions from Lab 3 into Lab 4 #include #include "os.h" #include "CortexM.h" #include "BSP.h" #include "../inc/tm4c123gh6pm.h" // function definitions in osasm.s void StartOS(void); #define NUMTHREADS 8 // maximum number of threads #define NUMPERIODIC 2 // maximum number of periodic threads #define STACKSIZE 100 // number of 32-bit words in stack per thread struct tcb{ int32_t *sp; // pointer to stack (valid for threads not running struct tcb *next; // linked-list pointer //*FILL THIS IN**** }; typedef struct tcb tcbType; tcbType tcbs[NUMTHREADS]; tcbType *RunPt; int32_t Stacks[NUMTHREADS][STACKSIZE]; void static runperiodicevents(void); // ******** OS_Init ************ // Initialize operating system, disable interrupts // Initialize OS controlled I/O: periodic interrupt, 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 // perform any initializations needed, // set up periodic timer to run runperiodicevents to implement sleeping } void SetInitialStack(int i){ // ****IMPLEMENT THIS**** // **Same as Lab 2 and Lab 3**** } //******** OS_AddThreads *************** // Add eight main threads to the scheduler // Inputs: function pointers to eight void/void main threads // priorites for each main thread (0 highest) // 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), uint32_t p0, void(*thread1)(void), uint32_t p1, void(*thread2)(void), uint32_t p2, void(*thread3)(void), uint32_t p3, void(*thread4)(void), uint32_t p4, void(*thread5)(void), uint32_t p5, void(*thread6)(void), uint32_t p6, void(*thread7)(void), uint32_t p7){ // **similar to Lab 3. initialize priority field**** return 1; // successful } void static runperiodicevents(void){ // ****IMPLEMENT THIS**** // **DECREMENT SLEEP COUNTERS // In Lab 4, handle periodic events in RealTimeEvents } //******** 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 } // runs every ms void Scheduler(void){ // every time slice // ****IMPLEMENT THIS**** // look at all threads in TCB list choose // highest priority thread not blocked and not sleeping // If there are multiple highest priority (not blocked, not sleeping) run these round robin } //******** OS_Suspend *************** // Called by main thread to cooperatively suspend operation // Inputs: none // Outputs: none // Will be run again depending on sleep/block status void OS_Suspend(void){ STCURRENT = 0; // any write to current clears it INTCTRL = 0x04000000; // trigger SysTick // next thread gets a full time slice } // ******** OS_Sleep ************ // place this thread into a dormant state // input: number of msec to sleep // output: none // OS_Sleep(0) implements cooperative multitasking void OS_Sleep(uint32_t sleepTime){ // ****IMPLEMENT THIS**** // set sleep parameter in TCB, same as Lab 3 // suspend, stops running } // ******** 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){ // ****IMPLEMENT THIS**** // Same as Lab 3 } // ******** OS_Wait ************ // Decrement semaphore and block if less than zero // 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){ // ****IMPLEMENT THIS**** // Same as Lab 3 } // ******** 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){ // ****IMPLEMENT THIS**** // Same as Lab 3 } #define FSIZE 10 // can be any size uint32_t PutI; // index of where to put next uint32_t GetI; // index of where to get next uint32_t Fifo[FSIZE]; int32_t CurrentSize;// 0 means FIFO empty, FSIZE means full uint32_t LostData; // number of lost pieces of data // ******** OS_FIFO_Init ************ // Initialize FIFO. The "put" and "get" indices initially // are equal, which means that the FIFO is empty. Also // initialize semaphores to track properties of the FIFO // such as size and busy status for Put and Get operations, // which is important if there are multiple data producers // or multiple data consumers. // Inputs: none // Outputs: none void OS_FIFO_Init(void){ // ****IMPLEMENT THIS**** // Same as Lab 3 } // ******** OS_FIFO_Put ************ // Put an entry in the FIFO. Consider using a unique // semaphore to wait on busy status if more than one thread // is putting data into the FIFO and there is a chance that // this function may interrupt itself. // Inputs: data to be stored // Outputs: 0 if successful, -1 if the FIFO is full int OS_FIFO_Put(uint32_t data){ // ****IMPLEMENT THIS**** // Same as Lab 3 return 0; // success } // ******** OS_FIFO_Get ************ // Get an entry from the FIFO. Consider using a unique // semaphore to wait on busy status if more than one thread // is getting data from the FIFO and there is a chance that // this function may interrupt itself. // Inputs: none // Outputs: data retrieved uint32_t OS_FIFO_Get(void){uint32_t data; // ****IMPLEMENT THIS**** // Same as Lab 3 return data; } // *****periodic events**************** int32_t *PeriodicSemaphore0; uint32_t Period0; // time between signals int32_t *PeriodicSemaphore1; uint32_t Period1; // time between signals void RealTimeEvents(void){int flag=0; static int32_t realCount = -10; // let all the threads execute once // Note to students: we had to let the system run for a time so all user threads ran at least one // before signalling the periodic tasks realCount++; if(realCount >= 0){ if((realCount%Period0)==0){ OS_Signal(PeriodicSemaphore0); flag = 1; } if((realCount%Period1)==0){ OS_Signal(PeriodicSemaphore1); flag=1; } if(flag){ OS_Suspend(); } } } // ******** OS_PeriodTrigger0_Init ************ // Initialize periodic timer interrupt to signal // Inputs: semaphore to signal // period in ms // priority level at 0 (highest // Outputs: none void OS_PeriodTrigger0_Init(int32_t *semaPt, uint32_t period){ PeriodicSemaphore0 = semaPt; Period0 = period; BSP_PeriodicTask_InitC(&RealTimeEvents,1000,0); } // ******** OS_PeriodTrigger1_Init ************ // Initialize periodic timer interrupt to signal // Inputs: semaphore to signal // period in ms // priority level at 0 (highest // Outputs: none void OS_PeriodTrigger1_Init(int32_t *semaPt, uint32_t period){ PeriodicSemaphore1 = semaPt; Period1 = period; BSP_PeriodicTask_InitC(&RealTimeEvents,1000,0); } //****edge-triggered event************ int32_t *edgeSemaphore; // ******** OS_EdgeTrigger_Init ************ // Initialize button1, PD6, to signal on a falling edge interrupt // Inputs: semaphore to signal // priority // Outputs: none void OS_EdgeTrigger_Init(int32_t *semaPt, uint8_t priority){ edgeSemaphore = semaPt; //***IMPLEMENT THIS*** // 1) activate clock for Port D // allow time for clock to stabilize // 2) no need to unlock PD6 // 3) disable analog on PD6 // 4) configure PD6 as GPIO // 5) make PD6 input // 6) disable alt funct on PD6 // disable pull-up on PD6 // 7) enable digital I/O on PD6 // (d) PD6 is edge-sensitive // PD6 is not both edges // PD6 is falling edge event // (e) clear PD6 flag // (f) arm interrupt on PD6 // priority on Port D edge trigger is NVIC_PRI0_R 31 – 29 // enable is bit 3 in NVIC_EN0_R } // ******** OS_EdgeTrigger_Restart ************ // restart button1 to signal on a falling edge interrupt // rearm interrupt // Inputs: none // Outputs: none void OS_EdgeTrigger_Restart(void){ //***IMPLEMENT THIS*** // rearm interrupt 3 in NVIC // clear flag6 } void GPIOPortD_Handler(void){ //***IMPLEMENT THIS*** // step 1 acknowledge by clearing flag // step 2 signal semaphore (no need to run scheduler) // step 3 disarm interrupt to prevent bouncing to create multiple signals }