For Cortex-M3,Cortex-M0, Multitask scheduler library. Arduino due compatible
Dependents: scheduler-demo-cq-lpc11u35 scheduler-demo scheduler-demo-cq-lpc11u35 mbed-scli-test
Scheduler.cpp
00001 /* 00002 * Copyright (C) 2012-2013 audin 00003 * This program is licensed under the Apache License, Version 2.0. 00004 * 2013/08: Modify for mbed for LPC1114FN28 00005 * Modified 2012/10: For working on Cortex-M0 and M3. 00006 * Defined static tcb option for the cpu that has quite a less SRAM < 8kbyte. 00007 * 00008 * Original file is arduino-1.5\hardware\arduino\sam\libraries\Scheduler 00009 */ 00010 00011 /* 00012 * Copyright (C) 2012 The Android Open Source Project 00013 * 00014 * Licensed under the Apache License, Version 2.0 (the "License"); 00015 * you may not use this file except in compliance with the License. 00016 * You may obtain a copy of the License at 00017 * 00018 * http://www.apache.org/licenses/LICENSE-2.0 00019 * 00020 * Unless required by applicable law or agreed to in writing, software 00021 * distributed under the License is distributed on an "AS IS" BASIS, 00022 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00023 * See the License for the specific language governing permissions and 00024 * limitations under the License. 00025 */ 00026 00027 #include <stdint.h> 00028 #include "mbed.h" 00029 #include "Scheduler.h" 00030 00031 #define _ARM_CM0_ 1 /* 1: Cortex-M0 or M3, 0: Cortex-M3 */ 00032 #define _USE_MALLOC_ 0 /* 1: 8kbyte >= SRAM, 0: 8kbyte < SRAM */ 00033 00034 00035 #if _USE_MALLOC_ 00036 # include <stdlib.h> 00037 #endif 00038 00039 #ifdef __cplusplus 00040 extern "C" { 00041 #endif 00042 uint32_t millis(void); 00043 00044 #define NUM_REGS 10 // r4-r11, sp, lr 00045 00046 typedef struct CoopTask { 00047 uint32_t regs[NUM_REGS]; 00048 void* stackPtr; 00049 struct CoopTask* next; 00050 struct CoopTask* prev; 00051 } CoopTask; 00052 00053 #if !_USE_MALLOC_ 00054 static uint32_t id = 0; 00055 static CoopTask tcb[ COOP_TASK_NUM_MAX ]; 00056 static uint8_t task_stack[ COOP_TASK_NUM_MAX - 1 ][ MIN_STACK_SIZE ]; 00057 #endif 00058 00059 static CoopTask *cur = 0; 00060 00061 CoopTask* __attribute__((noinline)) coopSchedule(char taskDied) { 00062 CoopTask* next = cur->next; 00063 00064 #if _USE_MALLOC_ 00065 if (taskDied) { 00066 // Halt if last task died. 00067 if (next == cur) 00068 while (1) 00069 ; 00070 00071 // Delete task 00072 if (cur->stackPtr) 00073 free(cur->stackPtr); 00074 cur->next->prev = cur->prev; 00075 cur->prev->next = cur->next; 00076 free(cur); 00077 } 00078 #endif 00079 cur = next; 00080 return next; 00081 } 00082 #ifdef __CC_ARM 00083 __asm static void coopTaskStart(void) { 00084 import coopSchedule 00085 #if _ARM_CM0_ 00086 /* for Cortex-m0 */ 00087 mov r0, r5; 00088 blx r4; 00089 movs r0, #1; 00090 bl coopSchedule; 00091 /**** ldmia r0, {r4-r12, lr}; */ 00092 adds r0, r0, #16; 00093 ldmia r0!, {r4-r7}; /* get r7->r11, r6->r10, r5->r9, r4->r8 */ 00094 mov r11, r7; 00095 mov r10, r6; 00096 mov r9, r5; 00097 mov r8 , r4; 00098 00099 ldmia r0!, {r4-r5}; /* get r5->lr, r4->r12 */ 00100 mov lr, r5; 00101 mov r12, r4; 00102 00103 subs r0, r0, #40; /* set offset for r4, 40 = 10reg * 4byte */ 00104 ldmia r0!, {r4-r7}; /* get r7,r6,r5,r4 */ 00105 /**** end ldmia converted by Cortex-M0 instructions */ 00106 msr msp, r12; /* use main stack */ 00107 bx lr; 00108 #else 00109 /* for Cortex-m3 or ARM code cpu */ 00110 mov r0, r5; /* r5 = new task func */ 00111 blx r4; /* r4 = helper func */ 00112 movs r0, #1; 00113 bl coopSchedule; 00114 ldmia r0, {r4-r12, lr}; 00115 mov sp, r12; 00116 bx lr; 00117 #endif 00118 } 00119 #else 00120 static void __attribute__((naked)) __attribute__((noinline)) coopTaskStart(void) { 00121 #if _ARM_CM0_ 00122 /* for Cortex-m0 */ 00123 __asm ( 00124 "mov r0, r5;" 00125 "blx r4;" 00126 "mov r0, #1;" 00127 "bl coopSchedule;" 00128 /**** "ldmia r0, {r4-r12, lr};" */ 00129 "add r0, r0, #16;" 00130 "ldmia r0!, {r4-r7};" /* get r7->r11, r6->r10, r5->r9, r4->r8 */ 00131 "mov r11, r7;" 00132 "mov r10, r6;" 00133 "mov r9, r5;" 00134 "mov r8 , r4;" 00135 00136 "ldmia r0!, {r4-r5};" /* get r5->lr, r4->r12 */ 00137 "mov lr, r5;" 00138 "mov r12, r4;" 00139 00140 "sub r0, r0, #40;" /* set offset for r4, 40 = 10reg * 4byte */ 00141 "ldmia r0!, {r4-r7};" /* get r7,r6,r5,r4 */ 00142 /**** end ldmia converted by Cortex-M0 instructions */ 00143 "msr msp, r12;" /* use main stack */ 00144 "bx lr;" 00145 ); 00146 #else 00147 /* for Cortex-m3 or ARM code cpu */ 00148 asm ( 00149 "mov r0, r5;" /* r5 = new task func */ 00150 "blx r4;" /* r4 = helper func */ 00151 "mov r0, #1;" 00152 "bl coopSchedule;" 00153 "ldmia r0, {r4-r12, lr};" 00154 "mov sp, r12;" 00155 "bx lr;" 00156 ); 00157 #endif 00158 } 00159 #endif 00160 00161 #ifdef __CC_ARM 00162 __asm static void coopDoYield(CoopTask* curTask) { 00163 #if _ARM_CM0_ 00164 /* for Cortex-m0 */ 00165 mrs r12, msp; 00166 /**** stmia r0, {r4-r12, lr}; */ 00167 stmia r0!, {r4-r7}; /* first store r4-r7 data */ 00168 00169 mov r4, r8; 00170 mov r5, r9; 00171 mov r6, r10; 00172 mov r7, r11; 00173 stmia r0!, {r4-r7}; /* store r8-r11 */ 00174 00175 mov r4, r12; 00176 mov r5, lr; 00177 stmia r0!, {r4,r5}; /* store r12, lr */ 00178 /**** end stmia converted by cortex-m0 instructions */ 00179 00180 movs r0, #0; 00181 bl coopSchedule; 00182 00183 /**** ldmia r0, {r4-r12, lr}; */ 00184 adds r0, r0, #16; /* set offset for r8 */ 00185 ldmia r0!, {r4-r7}; /* get r7->r11, r6->r10, r5->r9, r4->r8 */ 00186 mov r11, r7; 00187 mov r10, r6; 00188 mov r9, r5; 00189 mov r8 , r4; 00190 00191 ldmia r0!, {r4-r5}; /* get r5->lr, r4->r12 */ 00192 mov lr, r5; 00193 mov r12, r4; 00194 00195 subs r0, r0, #40; /* set offset for r4, 40 = 10reg * 4byte */ 00196 ldmia r0!, {r4-r7}; 00197 /**** end ldmia converted by Cortex-M0 instructions */ 00198 00199 msr msp, r12; 00200 bx lr; 00201 #else 00202 /* for Cortex-m3 or ARM code cpu */ 00203 mov r12, sp; 00204 stmia r0, {r4-r12, lr}; 00205 movs r0, #0; 00206 bl coopSchedule; 00207 ldmia r0, {r4-r12, lr}; 00208 mov sp, r12; 00209 bx lr; 00210 #endif 00211 } 00212 00213 #else 00214 static void __attribute__((naked)) __attribute__((noinline)) coopDoYield(CoopTask* curTask) { 00215 #if _ARM_CM0_ 00216 /* for Cortex-m0 */ 00217 __asm ( 00218 "mrs r12, msp;" 00219 /**** "stmia r0, {r4-r12, lr};" */ 00220 "stmia r0!, {r4-r7};" /* first store r4-r7 data */ 00221 00222 "mov r4, r8;" 00223 "mov r5, r9;" 00224 "mov r6, r10;" 00225 "mov r7, r11;" 00226 "stmia r0!, {r4-r7};" /* store r8-r11 */ 00227 00228 "mov r4, r12;" 00229 "mov r5, lr;" 00230 "stmia r0!, {r4,r5};" /* store r12, lr */ 00231 /**** end stmia converted by cortex-m0 instructions */ 00232 00233 "mov r0, #0;" 00234 "bl coopSchedule;" 00235 00236 /**** "ldmia r0, {r4-r12, lr};" */ 00237 "add r0, r0, #16;" /* set offset for r8 */ 00238 "ldmia r0!, {r4-r7};" /* get r7->r11, r6->r10, r5->r9, r4->r8 */ 00239 "mov r11, r7;" 00240 "mov r10, r6;" 00241 "mov r9, r5;" 00242 "mov r8 , r4;" 00243 00244 "ldmia r0!, {r4-r5};" /* get r5->lr, r4->r12 */ 00245 "mov lr, r5;" 00246 "mov r12, r4;" 00247 00248 "sub r0, r0, #40;" /* set offset for r4, 40 = 10reg * 4byte */ 00249 "ldmia r0!, {r4-r7};" 00250 /**** end ldmia converted by Cortex-M0 instructions */ 00251 00252 "msr msp, r12;" 00253 "bx lr;" 00254 ); 00255 #else 00256 /* for Cortex-m3 or ARM code cpu */ 00257 __asm ( 00258 "mov r12, sp;" 00259 "stmia r0, {r4-r12, lr};" 00260 "mov r0, #0;" 00261 "bl coopSchedule;" 00262 "ldmia r0, {r4-r12, lr};" 00263 "mov sp, r12;" 00264 "bx lr;" 00265 ); 00266 #endif 00267 00268 } 00269 #endif 00270 static int coopInit(void) { 00271 CoopTask* task; 00272 #if _USE_MALLOC_ 00273 # ifdef __cplusplus 00274 task = reinterpret_cast<CoopTask *>(malloc(sizeof(CoopTask))); 00275 # else 00276 task = (CoopTask *)(malloc(sizeof(CoopTask))); 00277 # endif 00278 if (!task) 00279 return 0; 00280 #else 00281 task = &tcb[ id ]; 00282 #endif 00283 task->next = task; 00284 task->prev = task; 00285 task->stackPtr = 0; 00286 cur = task; 00287 00288 return 1; 00289 } 00290 00291 static int coopSpawn(SchedulerParametricTask taskF, void* taskData, uint32_t stackSz) { 00292 #if _USE_MALLOC_ 00293 uint8_t *stack = (uint8_t*)malloc(stackSz); 00294 if (!stack) 00295 return 0; 00296 # ifdef __cplusplus 00297 CoopTask *task = reinterpret_cast<CoopTask *>(malloc(sizeof(CoopTask))); 00298 # else 00299 CoopTask *task = (CoopTask *)(malloc(sizeof(CoopTask))); 00300 # endif 00301 if (!task) { 00302 free(stack); 00303 return 0; 00304 } 00305 #else 00306 uint8_t *stack = task_stack[ id ]; 00307 id++; 00308 CoopTask *task = &tcb[ id ]; 00309 #endif 00310 task->stackPtr = stack; 00311 task->regs[0] = (uint32_t) taskF; /* Helper func: r4 */ 00312 task->regs[1] = (uint32_t) taskData; /* New task : r5 */ 00313 #if _USE_MALLOC_ 00314 task->regs[8] = ((uint32_t)(stack + stackSz)) & ~7; 00315 #else 00316 task->regs[8] = ((uint32_t)(stack + MIN_STACK_SIZE)) & ~7; /* r12 */ 00317 #endif 00318 task->regs[9] = (uint32_t) & coopTaskStart; /* lr */ 00319 00320 task->prev = cur; 00321 task->next = cur->next; 00322 cur->next->prev = task; 00323 cur->next = task; 00324 00325 // These are here so compiler is sure that function is 00326 // referenced in both variants (cancels a warning) 00327 if (stackSz == 0xFFFFFFFF) 00328 coopSchedule(0); 00329 if (stackSz == 0xFFFFFFFE) 00330 coopSchedule(1); 00331 00332 return 1; 00333 } 00334 00335 void yield(void) { 00336 coopDoYield(cur); 00337 } 00338 00339 #ifdef MBED_H 00340 void taskWait(uint32_t ms) { 00341 uint32_t start = us_ticker_read(); 00342 while ((us_ticker_read() - start) < (uint32_t)(ms*1000)){ 00343 yield(); 00344 } 00345 } 00346 #else 00347 void wait(uint32_t ms) { 00348 uint32_t start = millis(); 00349 while (millis() - start < ms){ 00350 yield(); 00351 } 00352 } 00353 #endif 00354 00355 #ifdef __cplusplus 00356 }; // extern "C" 00357 #endif 00358 00359 void scheduler_init( void ) { 00360 coopInit(); 00361 } 00362 00363 static void startLoopHelper(void *taskData) { 00364 #ifdef __cplusplus 00365 SchedulerTask task = reinterpret_cast<SchedulerTask>(taskData); 00366 #else 00367 SchedulerTask task = (SchedulerTask)(taskData); 00368 #endif 00369 while (1){ 00370 task(); 00371 } 00372 } 00373 00374 static void startTaskHelper(void *taskData) { 00375 #ifdef __cplusplus 00376 SchedulerTask task = reinterpret_cast<SchedulerTask>(taskData); 00377 #else 00378 SchedulerTask task = (SchedulerTask)(taskData); 00379 #endif 00380 task(); 00381 } 00382 00383 void scheduler_start( SchedulerTask task ) { 00384 coopSpawn( startTaskHelper, (void *)(task), MIN_STACK_SIZE ); 00385 } 00386 00387 void scheduler_startLoop( SchedulerTask task) { 00388 coopSpawn( startLoopHelper, (void *)(task), MIN_STACK_SIZE ); 00389 } 00390 00391 #ifdef __cplusplus 00392 SchedulerClass::SchedulerClass() { 00393 coopInit(); 00394 } 00395 00396 void SchedulerClass::startLoop(SchedulerTask task, uint32_t stackSize) { 00397 coopSpawn(startLoopHelper, reinterpret_cast<void *>(task), stackSize); 00398 } 00399 00400 void SchedulerClass::start(SchedulerTask task, uint32_t stackSize) { 00401 coopSpawn(startTaskHelper, reinterpret_cast<void *>(task), stackSize); 00402 } 00403 00404 void SchedulerClass::start(SchedulerParametricTask task, void *taskData, uint32_t stackSize) { 00405 coopSpawn(task, taskData, stackSize); 00406 } 00407 00408 SchedulerClass Scheduler; 00409 #endif 00410
Generated on Fri Jul 15 2022 11:49:31 by 1.7.2