/************************************************************************* This file is part of aOS. aOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. aOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with aOS; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Copyright 2001, 2002 Anssi Ylätalo ---------------------------------- Dec 2004 Modified by Bruce Land for 16 MHz clock on MEGA32 Moved clock enable code to after aos_start is called Moved stack definitions to user_task.h Modified t0 interrupt to check for AOS_TASK_DELAYD in decrement Modified _aos_schedule for readability comparing to RUNNABLE Fixed an if statement in timer0 ISR (missing brackets) --added time accumulation to scheduler--USES TIMER1 --added dispatch counter Removed savereg pragma on ISR removed all PORT assignments from core Updated asm to account for changed local variable storage in 1.24.6 **************************************************************************/ #pragma regalloc- aos_cent_tbl aos_ctbl; /* Central table */ aos_tcb all_tcb[AOS_TASK_MAX]; /* Pointers to Task Control Blocks */ aos_scb all_scb[AOS_SEM_MAX]; /* Pointers to Semaphore Control Blocks */ aos_mcb all_mcb[AOS_MBOX_MAX]; /* Pointers to Message Queue Control Blocks */ aos_tcb *NULL_TASK; /* Straight pointer to null-process' PCB */ /* Stacks for NULL task */ UBYTE DNULL[AOS_TASK_DSTK_SIZE], HWNULL[AOS_TASK_HSTK_SIZE]; #pragma regalloc+ /* Low level function which makes actual context switch */ void _aos_dispatch( void ) { UBYTE *dstk_highrdy, *hstk_highrdy; aos_tcb *curr_tcb; AOS_ENTER_CRITICAL; aos_ctbl.aos_dispcntr++; //BRL added dispatch counter curr_tcb = aos_ctbl.tcb_current; /* Get address to current TCB */ dstk_highrdy = aos_ctbl.tcb_runq->datastk; /* Get highest priority ready tasks data stack */ hstk_highrdy = aos_ctbl.tcb_runq->hwstk; /* Get highest priority ready task's hw stack */ //aos_ctbl.tcb_current = aos_ctbl.tcb_runq; /* Set highest priority ready task current */ aos_ctbl.tcb_current = aos_ctbl.tcb_runq; /* Make first in run-queue current */ aos_ctbl.tcb_current->status = AOS_TASK_RUNNING; /* Context switch. ; *dstk_highrdy -> Y+4 see updated version below ; *hstk_highrdy -> Y+2 ; *curr_tcb -> Y+0 1. Save HW SP and data SP to current task's PCB 2. Load SP from highest priority task's TCB 3. Restore context and return to new task */ #asm ; Save all registers except SW stack pointer PUSH R0 PUSH R1 PUSH R2 PUSH R3 PUSH R4 PUSH R5 PUSH R6 PUSH R7 PUSH R8 PUSH R9 PUSH R10 PUSH R11 PUSH R12 PUSH R13 PUSH R14 PUSH R15 PUSH R16 PUSH R17 PUSH R18 PUSH R19 PUSH R20 PUSH R21 PUSH R22 PUSH R23 PUSH R24 PUSH R25 PUSH R26 PUSH R27 PUSH R30 PUSH R31 IN R0,SREG PUSH R0 ; Save current HW stack pointer, low first ;LDD R26,Y+0 ; hstk_current -> X ;LDD R27,Y+1 mov r26,r20 mov r27,r21 IN R30,SPL ; *hstk_current = SP; ST X+,R30 IN R30,SPH ST X+,R30 ; Save current SW stack pointer, low first ;MOV R30,R28 ; LOW(Y) -> R30 ;ADIW R30,6 ; Restore Y value (3 pointers * 2 bytes each) ;ST X+,R30 ; *dstk_current = Y; ;ST X,R29 adiw r28, 6 st x+, r28 st x, r29 ; Load new HW stack pointer, low first ;LDD R30,Y+2 ;OUT SPL,R30 ;LDD R30,Y+3 ;OUT SPH,R30 out SPL, r18 out SPH, r19 ; Load new SW stack pointer, low first ;LDD R30,Y+4 ;LDD R31,Y+5 ;MOV R28,R30 ;MOV R29,R31 mov r28, r16 mov r29, r17 ; Pop all registers except SW stack pointer POP R0 OUT SREG,R0 POP R31 POP R30 POP R27 POP R26 POP R25 POP R24 POP R23 POP R22 POP R21 POP R20 POP R19 POP R18 POP R17 POP R16 POP R15 POP R14 POP R13 POP R12 POP R11 POP R10 POP R9 POP R8 POP R7 POP R6 POP R5 POP R4 POP R3 POP R2 POP R1 POP R0 RETI #endasm } void _aos_schedule( void ) { aos_tcb *tptr, *highest_tcb; UBYTE highest; //don't do anything if scheduler is off if (!(aos_ctbl.aos_schedrun)) return; AOS_ENTER_CRITICAL; if (AOS_CHCK) //Uses TIMER1!!!! { TCCR1B=0; aos_ctbl.tcb_current->ttime+=(unsigned long)TCNT1 ; /*BRL added: Increment current task time*/ } highest = 255; /* NULL-task's priority */ NULL_TASK->status = AOS_TASK_RUNNABLE; /* NULL-task is always runnable */ if( aos_ctbl.tcb_current->status == AOS_TASK_RUNNING ) /* If current task is running here */ aos_ctbl.tcb_current->status = AOS_TASK_RUNNABLE; /* it is still runnable */ tptr = (aos_tcb *)aos_ctbl.tcb_used_list; /* Go through all runnable tasks */ //printf("\n\r"); do { //printf("%x %x \n\r",tptr, tptr->status); /* and get the one having highest priority */ // if( !tptr->status ) { if( AOS_TASK_RUNNABLE==tptr->status ) { /*MODIFIED Is task runnable? runnable=0 */ if( tptr->prio <= highest ) { /* Yes, is it's priority higher than highest allready? */ highest = tptr->prio; /* Yes, save it */ highest_tcb = (aos_tcb *)tptr; } } tptr = (aos_tcb *)tptr->next_tcb; } while( tptr ); /* Was it last one? */ aos_ctbl.tcb_runq = (aos_tcb *)highest_tcb; /* Put highest priority task in run-queue */ if( aos_ctbl.tcb_current != aos_ctbl.tcb_runq ) /* If next in run-queue is different task */ _aos_dispatch(); /* we have to dispatch */ if (AOS_CHCK) //USES timer 1!!! { TCNT1=0; TCCR1B=5; } AOS_EXIT_CRITICAL; } // Timer 0 output compare interrupt service routine /* Timer tick ISR */ interrupt [TIM0_COMP] void timer0_comp_isr(void) { volatile aos_tcb *tptr; volatile UBYTE sched_n_disp; //printf("DD"); AOS_ENTER_CRITICAL; if( aos_ctbl.aos_running ) { /* Is multitasking on? */ sched_n_disp = 0; /* Flag of need for scheduling and dispatching */ tptr = (aos_tcb *)aos_ctbl.tcb_used_list; /* Point to first TCB */ do { /* Go through all PCBs */ //if( tptr->delay && tptr->status==AOS_TASK_DELAYD) { //MODIFIED statment //if( tptr->delay ) { /* Delay for this task? */ if(tptr->status==AOS_TASK_DELAYD){ //Is the task sleeping? if(tptr->delay>0) //Still some time left? tptr->delay--; /* Yes, decrement */ else { //no, make it runnable tptr->status = AOS_TASK_RUNNABLE; /*make the task runnable again */ sched_n_disp = 1; /*re-schedule */ } } tptr = (aos_tcb *)tptr->next_tcb; /* Get next TCB */ } while( tptr ); /* Last in PCB chain? */ aos_ctbl.aos_systime++; /* Increment system uptime */ if( sched_n_disp ) { /* If some task became runnable */ _aos_schedule(); /* we have to re-schedule */ } } AOS_EXIT_CRITICAL; } #pragma warn- void _init_free_list( void ) { UBYTE i; aos_tcb *tcb_this, *tcb_next; aos_scb *scb_this, *scb_next; aos_mcb *mcb_this, *mcb_next; AOS_ENTER_CRITICAL; /* Process PCBs */ for(i=0;inext_tcb = (aos_tcb *)tcb_next; } all_tcb[AOS_TASK_MAX].next_tcb = (aos_tcb *)0; /* Last PCB in chain */ /* Process SCBs */ for(i=0;inext_scb = (aos_scb *)scb_next; } all_scb[AOS_SEM_MAX].next_scb = (aos_scb *)0; /* Last SCB in chain */ /* Process MCBs */ for(i=0;inext_mcb = (aos_mcb *)mcb_next; } all_mcb[AOS_MBOX_MAX].next_mcb = (aos_mcb *)0; /* Last SCB in chain */ AOS_EXIT_CRITICAL; } #pragma warn+ void aos_start( void ) { if( aos_ctbl.tcb_used_list ) { /* Is there tasks created? */ aos_ctbl.aos_running = 1; /* Start multi-tasking */ } } void aos_sleep( UWORD ticks ) { AOS_ENTER_CRITICAL; aos_ctbl.tcb_current->delay = ticks; /* Put task to sleep for 'ticks' time. */ aos_ctbl.tcb_current->status = AOS_TASK_DELAYD; _aos_schedule(); AOS_EXIT_CRITICAL; } ULONG aos_uptime( void ) { return( aos_ctbl.aos_systime ); } void NULLTASK( void ) { //aos_tcb *tptr; //ULONG i ; while( 1 ) { //AOS_ENTER_CRITICAL //aos_ctbl.aos_idlecntr++; //AOS_EXIT_CRITICAL //PORTB.7 = 0; //for(i=0;i<100000;i++) {}; // PORTB.7 = 1; // for(i=0;i<100000;i++) {}; } } //void task1(void); #pragma regalloc- aos_tcb *cmd_tcb; #pragma regalloc+ void main(void) { UBYTE *nt_dstk, *nt_hstk; /* NULL-task's stacks */ //************************************* //Application dependent setup //most of this should be moved to task definitions //(EXECPT for timer 0 setup // Timer/Counter 0 initialization // Clock source: System Clock // Clock value: 16 MHz // Mode: Output Compare //OC0 output: Disconnected // Timer/Counter 0 is cleared on compare match //TCCR0=0b00001101; move to NULLTASK to start clock //ASSR=0x00; TCNT0=0x00; //The following sets the task-switch rate!!! //divide by 1024 means 1 tick is //64 microseconds x 250 = 16 mSec OCR0=15.6 * AOS_TICK_TIME; //64 usec x 156 = 10mSec //OCR0=78 ; //5 ms //OCR0=39 ; //2.5 ms //OCR0=20 ; //1.25 ms //OCR0=0 ; //960 usec //BUT don't start clock until OS is started // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x02; //timer 0 compare match /* Initialize PCB & SCB freelist */ _init_free_list(); /* Set up AOS central table */ aos_ctbl.aos_running = 0; /* Not running */ aos_ctbl.aos_schedrun = 1; //enable scheduler aos_ctbl.tcb_used_list = (aos_tcb *)0; /* No created processes yet */ aos_ctbl.tcb_free_list = (aos_tcb *)&all_tcb[0]; /* First TCB in free list */ aos_ctbl.scb_used_list = (aos_scb *)0; /* No created semaphores yet */ aos_ctbl.scb_free_list = (aos_scb *)&all_scb[0]; /* First SCB in free list */ aos_ctbl.mcb_used_list = (aos_mcb *)0; /* No created mailboxes yet */ aos_ctbl.mcb_free_list = (aos_mcb *)&all_mcb[0]; /* First MCB in free list */ /* Allways create NULL task which is allways runnable */ /* and which has the lowest priority */ NULL_TASK = aos_task_create( NULLTASK, HWNULL, DNULL, 255 ); /* Use NULL-task's stacks prior to first context switch */ nt_dstk = (UBYTE *)NULL_TASK->datastk; nt_hstk = (UBYTE *)NULL_TASK->hwstk; #asm ; Load new HW stack pointer, low first 1.23.8 version ;LDD R30,Y+0 ;OUT SPL,R30 ;LDD R30,Y+1 ;OUT SPH,R30 ; Load new data stack pointer, low first? 1.23.8 version ;LDD R30,Y+2 ;LDD R31,Y+3 ;MOV R28,R30 ;MOV R29,R31 ; Load new HW stack pointer, low first OUT SPL,r18 OUT SPH,r19 ; Load new data stack pointer, low first? MOV R28,r16 MOV R29,r17 #endasm aos_ctbl.tcb_current = (aos_tcb *)NULL_TASK; //*************************************************** /* Create at least one user task Modify for task and stack names if nescessary*/ //aos_task_create( task1, hw_stack1, data_stack1, 50 ); cmd_tcb = aos_task_create(AOS_FIRST_TASK_NAME, AOS_FIRST_TASK_HSTACK_NAME ,AOS_FIRST_TASK_DSTACK_NAME, AOS_FIRST_TASK_PRIO); //*************************************************** //PORTB=0xFF; /* Start multitasking */ aos_start(); TCNT0=0; TCCR0=0b00001101; //start the clock after multitasking is started _aos_schedule(); /* This causes program to jump actual NULL process */ #asm POP R0 OUT SREG,R0 POP R31 POP R30 POP R27 POP R26 POP R25 POP R24 POP R23 POP R22 POP R21 POP R20 POP R19 POP R18 POP R17 POP R16 POP R15 POP R14 POP R13 POP R12 POP R11 POP R10 POP R9 POP R8 POP R7 POP R6 POP R5 POP R4 POP R3 POP R2 POP R1 POP R0 RETI #endasm while (1) { /* We won't never, ever reach this point */ #asm("nop"); }; }