#ifdef LPC1756 #include "LPC17xx.bas" #elif defined LPC11U37 #include "LPC11U3x.bas" #elif defined LPC54102 #include "LPC54102.bas" #elif defined LPC1114 #include "LPC11xx.bas" #else #error this CPU not supported yet #endif #include "ASMinlineBASIC.bas" #define MAX_TASK 4 ' interrupt stack frame ARM INT pushes 8, INTERRUPT SUB pushes 8 + LR #define INT_FRAME (17-1) #define RETURN_PC ((INT_FRAME-1)*4) #define INIT_PSR &H61000000 ' seems to be initial PSR #define RETURN_INT &HFFFFFFF9 ' when returns to this value -- interrupt return dim taskSP (MAX_TASK-1) ' saved SP here dim taskTIME(MAX_TASK-1) ' in msec task_num = 0 ' cycles through the tasks saveMainPC = 0 task0PC = 0 ' will be set to task0 INTERRUPT SUB TIMER1IRQ dim save_r7 ' this is just an arbitrary name, BASIC expression results end up in save_r7 if (task_num = -1) then ' special case on startup -- return to task0, save the return to main for task0 exit ASM_LDR_SPI(r7,RETURN_PC) ' save_r7 now has PC for main saveMainPC = __ASM__ ' save it in saveMainPC save_r7 = task0PC ASM_STR_SPI(r7,RETURN_PC) ' set the return to task0: ASM_MOV(r7,sp) ' r7 now has value of SP save_r7 = __ASM__ ' calculating the next (index) clobbers save_r7, so save it taskSP(0) = save_r7 ' save current SP in taskSP(0) else ASM_MOV(r7,sp) ' r7 now has value of SP save_r7 = __ASM__ ' calculating the next (index) clobbers save_r7, so save it taskSP(task_num) = save_r7 ' save it in taskSP(tasknum) endif task_num += 1 if task_num = MAX_TASK then task_num = 0 save_r7 = taskSP(task_num) ASM_MOV(sp,r7) ' move SP to next task stack T1_TC = 0 ' otherwise might be past MR0 T1_MR0 = taskTIME(task_num)-1 ' set the time alotted to the task T1_IR = 1 ' Clear interrupt ENDSUB SUB ON_TIMER ( max_cnt, dothis ) ' max_cnt in msec #if defined LPC1756 || defined LPC1751 TIMER1_ISR = dothis + 1 'set function of VIC -- need the +1 for Thumb operation T1_PR = 24999 '1 ms prescale VICIntEnable or= (1<<2) 'Enable interrupt #elif defined LPC11U37 TIMER1_ISR = dothis + 1 'set function of VIC -- need the +1 for Thumb operation SYSCON_SYSAHBCLKCTRL OR= (1<<10) ' enable TIMER1 T1_PR = 24999 '1 ms prescale VICIntEnable OR= (1<<TIMER1_IRQn) 'Enable interrupt #elif defined LPC54102 TIMER1_ISR = dothis + 1 'set function of VIC -- need the +1 for Thumb operation ASYNCAPBCLKCTRLSET = SYSCON_CLOCK_TIMER1 ' enable TIMER1 T1_PR = 12499 '1 ms prescale VICIntEnSet0 = (1<<TIMER1_IRQn) 'Enable interrupt #elif defined LPC1114 TIMER1_ISR = dothis + 1 'set function of VIC -- need the +1 for Thumb operation T1_PR = 49999 '1 ms prescale VICIntEnable or= (1<<19) 'Enable interrupt REMEMBER for LPC11xx we swapped 0/1 with 2/3 #else #warning -- need special setup for this CPU #endif T1_MR0 = max_cnt-1 ' set up match number of ms T1_MCR = 3 ' Interrupt and Reset on MR0 T1_IR = 1 ' clear interrupt T1_TC = 0 ' clear timer counter T1_TCR = 1 ' TIMER1 Enable ENDSUB #define STACK_SZ 127 ' probably don't need this much room -- each task needs a seperate stack ' task0 uses the main stack DIM stack1 (STACK_SZ) DIM stack2 (STACK_SZ) DIM stack3 (STACK_SZ) ' tasks can not share subroutines/functions that have parameters or locals, as those are NOT re-entrant sub task0 ' task0 is the first called, using main stack, and handles an exit semi-gracefully dim x while 1 IO(6)=0 IO(6)=1 x = x + 1 if x > &H100000 then exit loop T1_TCR = 0 ' TIMER1 disable x = saveMainPC + 3 ' LSB Thumb indicator, and return past BR self ASM_PUSH(_r7) ' and this will be poped as PC end sub sub task1 while 1 ' tasks SHALL NEVER return -- equivalent of crossing the streams IO(7)=0 IO(7)=1 loop end sub sub task2 while 1 IO(8)=0 IO(8)=1 loop end sub sub task3 while 1 IO(9)=0 IO(9)=1 loop end sub main: task_num = -1 ' special case for initial task switch taskTIME(0) = 50 ' arbitrary time in msec for each task taskTIME(1) = 10 taskTIME(2) = 15 taskTIME(3) = 20 ASM_MOV(r7,r5) ' r5 used to calculate global addresses save_r5 = __ASM__ task0PC = ADDRESSOF(task0) + 1 ' first entry to timer interrupt uses this to patch return stack taskSP(1) = ADDRESSOF(stack1) + (STACK_SZ-INT_FRAME)*4 stack1(STACK_SZ) = INIT_PSR stack1(STACK_SZ-1) = ADDRESSOF(task1) + 1 stack1(STACK_SZ-8) = RETURN_INT ' INTERRUPT SUB pushes LR here stack1(STACK_SZ-11) = save_r5 ' used to access globals taskSP(2) = ADDRESSOF(stack2) + (STACK_SZ-INT_FRAME)*4 stack2(STACK_SZ) = INIT_PSR stack2(STACK_SZ-1) = ADDRESSOF(task2) + 1 stack2(STACK_SZ-8) = RETURN_INT ' INTERRUPT SUB pushes LR here stack2(STACK_SZ-11) = save_r5 ' used to access globals taskSP(3) = ADDRESSOF(stack3) + (STACK_SZ-INT_FRAME)*4 stack3(STACK_SZ) = INIT_PSR stack3(STACK_SZ-1) = ADDRESSOF(task3) + 1 stack3(STACK_SZ-8) = RETURN_INT ' INTERRUPT SUB pushes LR here stack3(STACK_SZ-11) = save_r5 ' used to access globals ON_TIMER (taskTIME(0), ADDRESSOF(TIMER1IRQ)) ' start timer1 interrupts ASM_BR(0) ' wait here until task0 turns off multitasking endTasks: print "we're back" STOP ' if you want to debug