void GPIOPortB_Handler(void) { // handle port B0 interrupt if ((GPIO_PORTB_MIS_R&0x01) == 0x01) { GPIO_PORTB_ICR_R = 0x01; // handle rising edge if ((GPIO_PORTB_IEV_R&0x01) == 0x01) { Sensor0StartTime = OS_Time(); GPIO_PORTB_IEV_R &= ~0x01; // switch to falling edge } else { // handle falling edge Sensor0Reading = OS_TimeDifference(Sensor0StartTime, OS_Time()); GPIO_PORTB_IM_R &= ~0x01; // disable PB0 interrupts GPIO_PORTB_IEV_R |= 0x01; // switch to rising edge (for next time) GPIO_PORTB_DIR_R |= 0x01; // make PB0 out (for next time) OS_bSignal(&Sensor0DataAvailable); } } // handle port B1 interrupt if ((GPIO_PORTB_MIS_R&0x02) == 0x02) { GPIO_PORTB_ICR_R = 0x02; // handle rising edge if ((GPIO_PORTB_IEV_R&0x02) == 0x02) { Sensor1StartTime = OS_Time(); GPIO_PORTB_IEV_R &= ~0x02; // switch to falling edge } else { // handle falling edge Sensor1Reading = OS_TimeDifference(Sensor1StartTime, OS_Time()); GPIO_PORTB_IM_R &= ~0x02; // disable PB1 interrupts GPIO_PORTB_IEV_R |= 0x02; // switch to rising edge (for next time) GPIO_PORTB_DIR_R |= 0x02; // make PB1 out (for next time) OS_bSignal(&Sensor1DataAvailable); } } }
void PseudoWork(unsigned short work){ unsigned long startTime; startTime = OS_Time(); // time in 100ns units timeDif = OS_TimeDifference(OS_Time(),startTime); while(timeDif <= (long)work) { timeDif = OS_TimeDifference(OS_Time(),startTime); } }
int main(void) { unsigned int id; unsigned long time; id = OS_Id(); PF2 ^= 0x04; Display_Message(0,line++, "Hello world: ", id); OS_AddThread(thread, 128, 1); time = OS_Time(); OS_Sleep(1000); time = (((OS_TimeDifference(time, OS_Time()))/1000ul)*125ul)/10000ul; Display_Message(0,line++, "Sleep time: ", time); PF2 ^= 0x04; OS_Kill(); }
void OS_SW2Jitter(uint32_t period) { unsigned static long LastTime; // time at previous ADC sample unsigned long thisTime; // time at current ADC sample long jitter; // time between measured and expected, in us uint8_t ignore = 0; thisTime = OS_Time(); // current time, 12.5 ns ignore++; // calculation finished if(ignore>1){ // ignore timing of first interrupt unsigned long diff = OS_TimeDifference(LastTime,thisTime); if(diff>period){ jitter = (diff-period+4)/8; // in 0.1 usec }else{ jitter = (period-diff+4)/8; // in 0.1 usec } if(jitter > SW2MaxJitter){ SW2MaxJitter = jitter; // in usec } // jitter should be 0 if(jitter >= SW2JitterSize){ jitter = JITTERSIZE-1; } SW2JitterHistogram[jitter]++; } LastTime = thisTime; }
void DAS(void) { int index; static int i = 0; unsigned short input; static unsigned long LastTime; // time at previous ADC sample unsigned long thisTime; // time at current ADC sample long jitter; // time between measured and expected if(NumSamples < RUNLENGTH){ // finite time run // GPIO_B0 ^= 0x01; input = ADC_In(1); thisTime = OS_Time(); // current time, 20 ns DASoutput = Filter(input); FilterWork++; // calculation finished if(FilterWork>1){ // ignore timing of first interrupt jitter = ((OS_TimeDifference(thisTime,LastTime)-PERIOD)*CLOCK_PERIOD)/1000; // in usec if(jitter > MaxJitter){ MaxJitter = jitter; } if(jitter < MinJitter){ MinJitter = jitter; } // jitter should be 0 index = jitter+JITTERSIZE/2; // us units if(index<0)index = 0; if(index>=JitterSize)index = JITTERSIZE-1; JitterHistogram[index]++; } LastTime = thisTime; } }
// ******** OS_SysTick_Handler ************ // Thread Switcher, uses SysTick as periodic timer, calls PendSV to actually switch threads // Implement Thread Manager implicitly here // input: none, uses globals RUNPT and NEXTRUNPT // output: none, should switch threads when finished void OS_SysTick_Handler(void){ tcbType *i, *j; int pri; int x; DisableInterrupts(); //Thread Scheduler if(RRSCHEDULER){ //ROUND ROBBIN SCHEDULER for(i=RUNPT->next; i->sleep>0 || i->blockedOn!=0; i=i->next){ //OLD SLEEP DECRIMENTER //if(i->sleep>0){//decriment sleep counter // i->sleep=i->sleep-1; //} } NEXTRUNPT=i; }else if(PRIORITYSCHEDULER){ //PRIORITY SCHEDULER pri=7; j=RUNPT->next; x=0; do{ x++; //find thread with highest priority that isnt sleeping or blocked if(j->blockedOn==NULL && j->sleep==0 && j->workingPriority<pri){ pri=j->workingPriority; i=j; } j=j->next; //}while(j!=RUNPT->next); }while(x<NUMTHREADS); /* //Priority Scheduler, failed for case where lowest thread got blocked. for(i=RUNPT->next,pri=RUNPT->workingPriority,x=0; i->sleep>0 || i->blockedOn!=NULL || (i->workingPriority > pri); i=i->next, x++){ //Possible ERROR HERE, needs rethought //search for next thread untill you find one that is not sleeping, not blocked, and has a priority equal or less than the current RUNPT if(x>=NUMTHREADS && pri<7){ x=0; pri++; } } */ //OLD SLEEP DECRIMENTER //if(i->sleep>0){//decriment sleep counter // i->sleep=i->sleep-1; //} NEXTRUNPT=i; RUNPT->lastRun=OS_Time(); RUNPT->workingPriority = RUNPT->realPriority; } EnableInterrupts(); //Switch Threads (trigger PendSV) NVIC_INT_CTRL_R = 0x10000000; //PendSV_Handler(); }
void DAS(void){ unsigned long input; unsigned static long LastTime; // time at previous ADC sample unsigned long thisTime; // time at current ADC sample long jitter; // time between measured and expected, in us if(NumSamples < RUNLENGTH){ // finite time run PE0 ^= 0x01; input = ADC_In(); // channel set when calling ADC_Init PE0 ^= 0x01; thisTime = OS_Time(); // current time, 12.5 ns DASoutput = Filter(input); FilterWork++; // calculation finished if(FilterWork>1){ // ignore timing of first interrupt unsigned long diff = OS_TimeDifference(LastTime,thisTime); if(diff>PERIOD){ jitter = (diff-PERIOD+4)/8; // in 0.1 usec }else{ jitter = (PERIOD-diff+4)/8; // in 0.1 usec } if(jitter > MaxJitter){ MaxJitter = jitter; // in usec } // jitter should be 0 if(jitter >= JitterSize){ jitter = JITTERSIZE-1; } JitterHistogram[jitter]++; } LastTime = thisTime; PE0 ^= 0x01; } }
//******** Robot *************** // foreground thread, accepts data from producer // inputs: none // outputs: none void Robot(void){ unsigned long data; // ADC sample, 0 to 1023 unsigned long voltage; // in mV, 0 to 3000 unsigned long time = 0; // in 10msec, 0 to 1000 unsigned long t=0; unsigned int i; //OS_ClearMsTime(); char string[100]; DataLost = 0; // new run with no lost data OSuart_OutString(UART0_BASE, "Robot running..."); eFile_Create("Robot"); eFile_RedirectToFile("Robot"); OSuart_OutString(UART0_BASE, "time(sec)\tdata(volts)\n\r"); for(i = 1000; i > 0; i--){ t++; time+=OS_Time()/10000; // 10ms resolution in this OS while(!OS_Fifo_Get(&data)); // 1000 Hz sampling get from producer voltage = (300*data)/1024; // in mV sprintf(string, "%0u.%02u\t\t%0u.%03u\n\r",time/100,time%100,voltage/1000,voltage%1000); OSuart_OutString(UART0_BASE, string); } eFile_EndRedirectToFile(); OSuart_OutString(UART0_BASE, "done.\n\r"); Running = 0; // robot no longer running OS_Kill(); }
// ******** Jitter2 *************** // records the jitter for the second periodic background thread void Jitter2(void) { int index; unsigned static long LastTime; static char First = TRUE; unsigned long thisTime; long jitter; thisTime = OS_Time(); if(First == FALSE) { jitter = (OS_TimeDifference(thisTime, LastTime) / 10) - (gThread2Period / 50); // in usec if(jitter > MaxJitter2) { MaxJitter2 = jitter; } if(jitter < MinJitter2) { MinJitter2 = jitter; } index = jitter + JITTERSIZE / 2; // us units if(index < 0) index = 0; if(index >= JitterSize) index = JITTERSIZE - 1; JitterHistogram2[index]++; } else { First = FALSE; } LastTime = thisTime; }
void Thread3d(void){ Count3 = 0; for(;;){ thisTime = NVIC_ST_CURRENT_R; Count3 = thisTime*2 - OS_Time(); } }
void OS_DelayUntil(int t) { int c = OS_Time(); if (RTOS_BITS == 32) { assert(1 <= (t - c) && (t - c) <= 0x7FFFFFFF); } else { /* RTOS_BITS == 8 or 16 */ assert(1 <= (t - c) && (t - c) <= 0x7FFF); } }
//----------------- PortB_Handler ----------------------- //occurs after PING_Signal arms ther interrupt void GPIOPortB_Handler(void){ static unsigned long startTime1, startTime2, startTime3, startTime4, data, time; time = OS_Time(); data = GPIO_PORTB_DATA_R; //--- PING 1 if((GPIO_PORTB_DATA_R & 0x10) == 0x10){ //PB4 high startTime1 = time; GPIO_PORTB_ICR_R = 0x10; //acknowledge flag4 } else if((GPIO_PORTB_DATA_R & 0x10) == 0){ //PB4 low PING_Time1 = OS_TimeDifference(startTime1, time); //OS_AddThread(PING_PeriodicTask,128,1); GPIO_PORTB_ICR_R = 0x10; // acknowledge flag4 } //--- PING 2 if((GPIO_PORTB_DATA_R & 0x20) == 0x20){ //PB5 high startTime2 = time; GPIO_PORTB_ICR_R = 0x20; //acknowledge flag5 } else if((GPIO_PORTB_DATA_R & 0x20) == 0){ //PB5 low PING_Time2 = OS_TimeDifference(startTime2, time); //OS_AddThread(PING_PeriodicTask,128,1); GPIO_PORTB_ICR_R = 0x20; // acknowledge flag5 } //--- PING 3 if((GPIO_PORTB_DATA_R & 0x40) == 0x40){ //PB6 high startTime3 = time; GPIO_PORTB_ICR_R = 0x40; // acknowledge flag6 } else if((GPIO_PORTB_DATA_R & 0x40) == 0){ //PB6 low PING_Time3 = OS_TimeDifference(startTime3, time); //OS_AddThread(PING_PeriodicTask,128,1); GPIO_PORTB_ICR_R = 0x40; // acknowledge flag6 } //--- PING 4 if((GPIO_PORTB_DATA_R & 0x80) == 0x80){ //PB7 high startTime4 = time; GPIO_PORTB_ICR_R = 0x80; // acknowledge flag7 } else if((GPIO_PORTB_DATA_R & 0x80) == 0){ //PB7 low PING_Time4 = OS_TimeDifference(startTime4, time); //OS_AddThread(PING_PeriodicTask,128,1); GPIO_PORTB_ICR_R = 0x80; // acknowledge flag7 } }
//******** OS_AddThread *************** // add a foregound thread to the scheduler // Inputs: pointer to a void/void foreground task // number of bytes allocated for its stack // priority (0 is highest) // Outputs: 1 if successful, 0 if this thread can not be added // stack size must be divisable by 8 (aligned to double word boundary) // In Lab 2, you can ignore both the stackSize and priority fields // In Lab 3, you can ignore the stackSize fields int OS_AddThread(void(*task)(void), unsigned long stackSize, unsigned long priority){ int x=0, found, status; /* // Find unused thread while(x<NUMTHREADS) if (tcbs[x++].used == 0) break; // No unused threads found if (x=NUMTHREADS) return 0; // Unused thread found. x+1=index of thread x--; if ()*/ for(x=0,found=0;(x<NUMTHREADS) && (found==0);x++){ //loop untill you find a non used thread if(tcbs[x].used==0){ TOTALNUMTHREADS++; found=1; status=StartCritical(); //possible critical section? OS_ThreadInit(&tcbs[x],0xFFFA-x); tcbs[x].used=1; if(NumCreated==0){ //First Thread Ever, needs special case for it's RUNPT, b/c there is no run pointer previously RUNPT=&tcbs[x]; //set run pointer to point to initial thread tcbs[x].next=RUNPT; //it is only thread, so it points to itself for prev and next tcbs[x].prev=RUNPT; } else{ tcbs[x].next=RUNPT; // set prev / next on new thread tcbs[x].prev=RUNPT->prev; // RUNPT->prev->next=&tcbs[x]; // insert thread into current linked list of running threads RUNPT->prev=&tcbs[x]; // } tcbs[x].stack[STACKSIZE-2]=(long)task; //POSSIBLE ERROR, PC=task, i think this works... right?? EndCritical(status); //end of possible critical section? tcbs[x].realPriority=priority; tcbs[x].workingPriority=priority; tcbs[x].id=++IDCOUNT; tcbs[x].lastRun = OS_Time(); //TODO: implement adjustable stacksize using input variable 'stackSize' } } return found; }
// ******* OS_UpdateTimeInfoOnDisable ********** // Used in OS_DisableInterrupts and OS_StartCritical // Used to keep track of how much time is spent when interrupts are enabled. void OS_UpdateTimeInfoOnDisable(void) { if (continueMeasuring && OS_IsRunning) { unsigned long thisTime = OS_Time(); if (interruptsEnabled) { // interrupts were enabled. Calculate time spent in disabled mode if (lastEnableTime != 0) { if (thisTime >= lastEnableTime) { unsigned long diff = OS_TimeDifference(thisTime, lastEnableTime); if (enableTime > UINT32_T_MAX*80000 - diff) { continueMeasuring = 0; } // overflowed enableTime += diff; } // else there was an overflow in the timer } // else this was the first time disabling interrupts. Don't calculate anything //lastDisableTime = thisTime; } lastDisableTime = thisTime; } interruptsEnabled = 0; }
// ******* OS_UpdateTimeInfoOnEnable ********** // Used in OS_EnableInterrupts and OS_EndCritical // Used to keep track of how much time is spent when interrupts are disabled. void OS_UpdateTimeInfoOnEnable(void) { if (continueMeasuring && OS_IsRunning) { unsigned long thisTime = OS_Time(); // this is called when interrupts are going to be enabled // keep track of disabled time if (!interruptsEnabled) { // interrupts were disabled, calculate time spent in disabled mode if (lastDisableTime != 0) { if (thisTime >= lastDisableTime) { unsigned long diff = OS_TimeDifference(thisTime, lastDisableTime); if (disableTime > UINT32_T_MAX*80000 - diff) { continueMeasuring = 0; } disableTime += diff; if (diff > maxDisableTime) { maxDisableTime = diff; } } // else there was an overflow in the timer } // else this is the first time enabling interrupts. Don't calculate anything //lastEnableTime = thisTime; } // else do nothing lastEnableTime = thisTime; } interruptsEnabled = 1; }
// ******** Timer Handlers ************ // various timer handlers, used for periodic tasks and incrimenting system time // input: none, // output: none, // Timer0A Int Handler void Timer0A_Handler(){ //happens every 1ms int i; tcbType *j; // Clear Interrupt TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT); // Update global 1ms timer TIMELORD++; for(i=0,j=RUNPT;i<NUMTHREADS;i++,j=j->next){ //cycle through all threads deleteme++; // Decriment Sleep Timers on Everything if(j->sleep>0){ j->sleep = j->sleep-1; //deriment sleep counter } // Aging every 10ms if(j->lastRun - OS_Time() > AGING){ if(j->workingPriority-1 > 0){ j->workingPriority--; } } } }
// add the following commands, leave other commands, if they make sense // 1) print performance measures // time-jitter, number of data points lost, number of calculations performed // i.e., NumSamples, NumCreated, MaxJitter-MinJitter, DataLost, FilterWork, PIDwork //***************************************************************************** // // Interpret input from the terminal. Supported functions include // addition, subtraction, division, and multiplication in the post-fix format. // // \param nextChar specifies the next character to be put in the global buffer // // \return none. // //***************************************************************************** void OS_Interpret(unsigned char nextChar) { char operator = Buffer[BufferPt - 2]; char * token; char * last; char string[10]; int a; long total = 0; short first = 1; short command, equation = 0; switch(nextChar) { case '\b': if(BufferPt != 0) { BufferPt--; Buffer[BufferPt] = '\0'; } break; case '=': FirstSpace = 1; Buffer[BufferPt] = '='; equation = 1; break; case '\r': command = 1; //Buffer[BufferPt] = ' '; break; default: Buffer[BufferPt] = nextChar; BufferPt++; break; } if(equation == 1) { switch(operator) { case '+': for ( token = strtok_r(Buffer, " ", &last); token; token = strtok_r(NULL , " ", &last) ) { total = total + atoi(token); } Int2Str(total, string); OSuart_OutString(UART0_BASE, string); OSuart_OutString(UART0_BASE, "\r\n"); break; case '-': for ( token = strtok_r(Buffer, " ", &last); token; token = strtok_r(NULL , " ", &last) ) { if(first) { total = atoi(token); first = 0; } else { total = total - atoi(token); } } Int2Str(total, string); OSuart_OutString(UART0_BASE, string); OSuart_OutString(UART0_BASE, "\r\n"); break; case '*': for ( token = strtok_r(Buffer, " ", &last); token; token = strtok_r(NULL , " ", &last) ) { if(first) { total = atoi(token); first = 0; } else { if(atoi(token) != 0) { total = total * atoi(token); } } } Int2Str(total, string); OSuart_OutString(UART0_BASE, string); OSuart_OutString(UART0_BASE, "\r\n"); break; case '/': for ( token = strtok_r(Buffer, " ", &last); token; token = strtok_r(NULL , " ", &last) ) { if(first) { total = atoi(token); first = 0; } else { if(atoi(token) != 0) { total = total / atoi(token); } } } Int2Str(total, string); OSuart_OutString(UART0_BASE, string); OSuart_OutString(UART0_BASE, "\r\n"); break; case 't': Int2Str(OS_Time(), string); OSuart_OutString(UART0_BASE, string); OSuart_OutString(UART0_BASE, "\r\n"); break; case 'j': break; default: break; } equation = 0; BufferPt = 0; memset(Buffer,'\0',100); } if(command == 1) { // Interpret all of the commands in the line // time-jitter, number of data points lost, number of calculations performed // i.e., NumSamples, NumCreated, MaxJitter-MinJitter, DataLost, FilterWork, PIDwork for ( token = strtok_r(Buffer, " ", &last); token; token = strtok_r(NULL , " ", &last) ) { //strcat(token, "\"); //string = "PIDWork"; // Display the number of samples /*a = strcasecmp(token, "PIDWork"); Int2Str(a, string); OSuart_OutString(UART0_BASE, string);*/ if(strcasecmp(token, "NumSamples") == 0) { Int2Str(NumSamples, string); OSuart_OutString(UART0_BASE, " ="); OSuart_OutString(UART0_BASE, string); } // Display number of samples created if(strcasecmp(token, "NumCreated") == 0) { Int2Str(NumCreated, string); OSuart_OutString(UART0_BASE, " ="); OSuart_OutString(UART0_BASE, string); } // Displays delta jitter if(strcasecmp(token, "MaxJitter-MinJitter") == 0) { Int2Str(MaxJitter-MinJitter, string); OSuart_OutString(UART0_BASE, " ="); OSuart_OutString(UART0_BASE, string); } // Display the amount of data lost if(strcasecmp(token, "DataLost") == 0) { Int2Str(DataLost, string); OSuart_OutString(UART0_BASE, " ="); OSuart_OutString(UART0_BASE, string); } // Display the variable FilterWork if(strcasecmp(token, "FilterWork") == 0) { Int2Str(FilterWork, string); OSuart_OutString(UART0_BASE, " ="); OSuart_OutString(UART0_BASE, string); } // Display the variable PIDWork if(strcasecmp(token, "PIDWork") == 0) { Int2Str(PIDWork, string); OSuart_OutString(UART0_BASE, " ="); OSuart_OutString(UART0_BASE, string); } } command = 0; BufferPt = 0; memset(Buffer,'\0',100); OSuart_OutString(UART0_BASE, "\r\n"); } }
long JitterStart(void){ long thisTime; thisTime=OS_Time(); return thisTime; }
//*******PseudoWork************* // simple time delay, simulates user program doing real work // Input: amount of work in 100ns units (free free to change units // Output: none void PseudoWork(unsigned short work){ unsigned short startTime; startTime = OS_Time(); // time in 100ns units while(OS_TimeDifference(startTime,OS_Time()) <= work){} }