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

Files at this revision

API Documentation at this revision

Comitter:
dinau
Date:
Sun Aug 25 16:48:21 2013 +0900
Child:
1:8967b575bb46
Commit message:
for mbed

Changed in this revision

.hgignore Show annotated file Show diff for this revision Revisions of this file
Scheduler.cpp Show annotated file Show diff for this revision Revisions of this file
Scheduler.h Show annotated file Show diff for this revision Revisions of this file
keywords.txt Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Scheduler.cpp	Sun Aug 25 16:48:21 2013 +0900
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2012 audin
+ * This program is licensed under the Apache License, Version 2.0.
+ * Modified 2012/10: For working on Cortex-M0 and M3.
+ *                   Defined static tcb option for the cpu that has quite a less SRAM < 8kbyte.  
+ *
+ * Original file is arduino-1.5\hardware\arduino\sam\libraries\Scheduler
+ */
+
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include "Scheduler.h"
+
+#define _ARM_CM0_			1		/* 1: Cortex-M0 or M3,  0: Cortex-M3		*/
+#define _USE_MALLOC_		0		/* 1: 8kbyte >= SRAM,   0: 8kbyte < SRAM	*/
+
+
+#if _USE_MALLOC_
+#	include <stdlib.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+uint32_t millis(void);
+
+#define NUM_REGS 10	// r4-r11, sp, lr
+
+typedef struct CoopTask {
+	uint32_t regs[NUM_REGS];
+	void* stackPtr;
+	struct CoopTask* next;
+	struct CoopTask* prev;
+} CoopTask;
+
+#if  !_USE_MALLOC_
+static uint32_t id = 0;
+static CoopTask tcb[ COOP_TASK_NUM_MAX ];
+static uint8_t task_stack[ COOP_TASK_NUM_MAX - 1 ][ MIN_STACK_SIZE ];
+#endif
+
+static CoopTask *cur = 0;
+
+CoopTask* __attribute__((noinline)) coopSchedule(char taskDied) {
+	CoopTask* next = cur->next;
+
+#if _USE_MALLOC_
+	if (taskDied) {
+		// Halt if last task died.
+		if (next == cur)
+			while (1)
+				;
+
+		// Delete task
+		if (cur->stackPtr)
+			free(cur->stackPtr);
+		cur->next->prev = cur->prev;
+		cur->prev->next = cur->next;
+		free(cur);
+	}
+#endif
+	cur = next;
+	return next;
+}
+
+static void __attribute__((naked)) __attribute__((noinline)) coopTaskStart(void) {
+#if _ARM_CM0_
+	/* for Cortex-m0 */
+	__asm (
+		"mov   r0, r5;"
+		"blx   r4;"
+		"mov   r0, #1;"
+		"bl    coopSchedule;"
+	/****	"ldmia r0, {r4-r12, lr};"	*/
+		"add r0, r0, #16;"
+		"ldmia r0!, {r4-r7};"		/* get r7->r11, r6->r10, r5->r9, r4->r8		*/
+		"mov r11, r7;"
+		"mov r10, r6;"
+		"mov r9,  r5;"
+		"mov r8 , r4;"
+
+		"ldmia r0!, {r4-r5};"		/* get r5->lr, r4->r12						*/
+		"mov lr,  r5;"
+		"mov r12, r4;"
+
+		"sub r0, r0, #40;"			/* set offset for r4, 40 = 10reg * 4byte	*/
+		"ldmia  r0!, {r4-r7};"		/* get r7,r6,r5,r4							*/
+	/**** end ldmia converted by Cortex-M0 instructions	*/
+		"msr   msp, r12;"			/* use main stack							*/
+		"bx    lr;"
+	);
+#else
+	/* for Cortex-m3 or ARM code cpu */
+	asm (
+		"mov   r0, r5;"						/* r5 = new task func */
+		"blx   r4;"							/* r4 = helper func   */
+		"mov   r0, #1;"						
+		"bl    coopSchedule;"
+		"ldmia r0, {r4-r12, lr};"
+		"mov   sp, r12;"
+		"bx    lr;"
+	);
+#endif
+}
+
+static void __attribute__((naked)) __attribute__((noinline)) coopDoYield(CoopTask* curTask) {
+#if _ARM_CM0_
+	/* for Cortex-m0 */
+	__asm (
+			"mrs   r12, msp;"
+		/**** "stmia r0, {r4-r12, lr};" */
+			"stmia r0!, {r4-r7};"		/* first store r4-r7 data				*/
+
+			"mov r4, r8;"
+			"mov r5, r9;"
+			"mov r6, r10;"
+			"mov r7, r11;"
+			"stmia r0!, {r4-r7};"		/* store r8-r11							*/
+
+			"mov r4, r12;"
+			"mov r5, lr;"
+			"stmia r0!, {r4,r5};"		/* store r12, lr						*/
+		/**** end stmia converted by cortex-m0 instructions	*/
+
+			"mov   r0, #0;"
+			"bl    coopSchedule;"
+
+		/**** "ldmia r0, {r4-r12, lr};"	*/
+			"add r0, r0, #16;"			/* set offset for r8					*/
+			"ldmia r0!, {r4-r7};"		/* get r7->r11, r6->r10, r5->r9, r4->r8 */
+			"mov r11, r7;"
+			"mov r10, r6;"
+			"mov r9,  r5;"
+			"mov r8 , r4;"
+
+			"ldmia r0!, {r4-r5};"		/* get r5->lr, r4->r12					*/
+			"mov lr,  r5;"
+			"mov r12, r4;"
+
+			"sub r0, r0, #40;"			/* set offset for r4, 40 = 10reg * 4byte  */
+			"ldmia  r0!, {r4-r7};"
+		/**** end ldmia converted by Cortex-M0 instructions	*/
+
+			"msr   msp, r12;"
+			"bx    lr;"
+		);
+#else
+	/* for Cortex-m3 or ARM code cpu */
+	__asm (
+			"mov   r12, sp;"
+			"stmia r0, {r4-r12, lr};"
+			"mov   r0, #0;"
+			"bl    coopSchedule;"
+			"ldmia r0, {r4-r12, lr};"
+			"mov   sp, r12;"
+			"bx    lr;"
+		);
+#endif
+
+}
+
+static int coopInit(void) {
+	CoopTask* task;
+#if _USE_MALLOC_
+#	ifdef __cplusplus
+		task = reinterpret_cast<CoopTask *>(malloc(sizeof(CoopTask)));
+#	else
+		task = (CoopTask *)(malloc(sizeof(CoopTask)));
+#	endif
+	if (!task)
+		return 0;
+#else
+	task = &tcb[ id ];
+#endif
+	task->next = task;
+	task->prev = task;
+	task->stackPtr = 0;
+	cur = task;
+
+	return 1;
+}
+
+static int coopSpawn(SchedulerParametricTask taskF, void* taskData, uint32_t stackSz) {
+#if _USE_MALLOC_
+	uint8_t *stack = (uint8_t*)malloc(stackSz);
+	if (!stack)
+		return 0;
+#	ifdef __cplusplus
+		CoopTask *task = reinterpret_cast<CoopTask *>(malloc(sizeof(CoopTask)));
+#	else
+		CoopTask *task = (CoopTask *)(malloc(sizeof(CoopTask)));
+#	endif
+	if (!task) {
+		free(stack);
+		return 0;
+	}
+#else
+	uint8_t *stack = task_stack[ id ];
+	id++;
+	CoopTask *task = &tcb[ id ];
+#endif
+	task->stackPtr = stack;
+	task->regs[0] = (uint32_t) taskF;							/* Helper func: r4	*/
+	task->regs[1] = (uint32_t) taskData;						/* New task :	r5	*/
+#if _USE_MALLOC_
+	task->regs[8] = ((uint32_t)(stack + stackSz)) & ~7;
+#else
+	task->regs[8] = ((uint32_t)(stack + MIN_STACK_SIZE)) & ~7;		/* r12	*/
+#endif
+	task->regs[9] = (uint32_t) & coopTaskStart;					/* lr	*/
+
+	task->prev = cur;
+	task->next = cur->next;
+	cur->next->prev = task;
+	cur->next = task;
+
+	// These are here so compiler is sure that function is
+	// referenced in both variants (cancels a warning)
+	if (stackSz == 0xFFFFFFFF)
+		coopSchedule(0);
+	if (stackSz == 0xFFFFFFFE)
+		coopSchedule(1);
+
+	return 1;
+}
+
+void yield(void) {
+	coopDoYield(cur);
+}
+
+void wait(uint32_t ms) {
+	uint32_t start = millis();
+	while (millis() - start < ms)
+		yield();
+}
+
+#ifdef __cplusplus
+}; // extern "C"
+#endif
+
+void scheduler_init( void ) {
+	coopInit();
+}
+
+static void startLoopHelper(void *taskData) {
+#ifdef __cplusplus
+	SchedulerTask task = reinterpret_cast<SchedulerTask>(taskData);
+#else
+	SchedulerTask task = (SchedulerTask)(taskData);
+#endif
+	while (1){
+		task();
+	}
+}
+
+static void startTaskHelper(void *taskData) {
+#ifdef __cplusplus
+	SchedulerTask task = reinterpret_cast<SchedulerTask>(taskData);
+#else
+	SchedulerTask task = (SchedulerTask)(taskData);
+#endif
+	task();
+}
+
+void scheduler_start( SchedulerTask task ) {
+	coopSpawn( startTaskHelper, (void *)(task), MIN_STACK_SIZE );
+}
+
+void scheduler_startLoop( SchedulerTask task) {
+	coopSpawn( startLoopHelper, (void *)(task), MIN_STACK_SIZE );
+}
+
+#ifdef __cplusplus
+SchedulerClass::SchedulerClass() {
+	coopInit();
+}
+
+void SchedulerClass::startLoop(SchedulerTask task, uint32_t stackSize) {
+	coopSpawn(startLoopHelper, reinterpret_cast<void *>(task), stackSize);
+}
+
+void SchedulerClass::start(SchedulerTask task, uint32_t stackSize) {
+	coopSpawn(startTaskHelper, reinterpret_cast<void *>(task), stackSize);
+}
+
+void SchedulerClass::start(SchedulerParametricTask task, void *taskData, uint32_t stackSize) {
+	coopSpawn(task, taskData, stackSize);
+}
+
+SchedulerClass Scheduler;
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Scheduler.h	Sun Aug 25 16:48:21 2013 +0900
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2012 audin
+ * This program is licensed under the Apache License, Version 2.0.
+ * Modified 2012/11: v02:
+ *		Added external definition of stack size and task number. 
+ * Modified 2012/10: v01:
+ *		For working on Cortex-M0 and M3.
+ *		Defined static tcb option for the cpu that has quite a less SRAM < 8kbyte.
+ *
+ * Original file is arduino-1.5\hardware\arduino\sam\libraries\Scheduler
+ */
+
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _SCHEDULDER_H_
+#define _SCHEDULDER_H_
+
+/* 
+ * If you explicitly specify stack size, activate below,
+ * or used "Default settings"
+ */
+//#define SCHEDULER_TASK_NUM_MAX 4 
+//#define SCHEDULER_TASK_STACK_SIZE_EACH 200
+
+/* 
+ * Otherwise you can add compile option CFLAGS like this,  
+  -DSCHEDULER_TASK_NUM_MAX=4
+  -DSCHEDULER_TASK_STACK_SIZE_EACH=200
+*/
+
+/* Default settings */
+/******************************************************************************************/
+#ifndef SCHEDULER_TASK_NUM_MAX
+#define COOP_TASK_NUM_MAX 4 /* Define max task number( include main loop ) */
+#else
+#define COOP_TASK_NUM_MAX (SCHEDULER_TASK_NUM_MAX)
+#endif
+
+#ifndef SCHEDULER_TASK_STACK_SIZE_EACH
+#define MIN_STACK_SIZE (200) /* Minimum stack size per task, exclude main loop */
+#else
+#define MIN_STACK_SIZE (SCHEDULER_TASK_STACK_SIZE_EACH)
+#endif
+/* Thanks Ms.HI */
+/******************************************************************************************/
+
+#include <stdint.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+	typedef void (*SchedulerTask)(void);
+	typedef void (*SchedulerParametricTask)(void *);
+
+	void scheduler_init( void );
+	void scheduler_startLoop( SchedulerTask task );
+	void scheduler_start( SchedulerTask task );
+	
+	void wait(uint32_t ms);
+	void yield();
+#ifdef __cplusplus
+}
+#endif
+
+
+#if __cplusplus
+class SchedulerClass {
+public:
+	SchedulerClass();
+	static void startLoop(SchedulerTask task, uint32_t stackSize = MIN_STACK_SIZE);
+	static void start(SchedulerTask task, uint32_t stackSize = MIN_STACK_SIZE);
+	static void start(SchedulerParametricTask task, void *data, uint32_t stackSize = MIN_STACK_SIZE);
+
+	static void wait(uint32_t ms) { ::wait(ms); };
+	static void yield() { ::yield(); };
+};
+
+extern SchedulerClass Scheduler;
+
+#endif
+
+#endif	/* _SCHEDULDER_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/keywords.txt	Sun Aug 25 16:48:21 2013 +0900
@@ -0,0 +1,22 @@
+#######################################
+# Syntax Coloring Map For Scheduler
+#######################################
+
+#######################################
+# Datatypes (KEYWORD1)
+#######################################
+
+Scheduler	KEYWORD1
+
+#######################################
+# Methods and Functions (KEYWORD2)
+#######################################
+
+yield	KEYWORD2
+wait	KEYWORD2
+startLoop	KEYWORD2
+
+#######################################
+# Constants (LITERAL1)
+#######################################
+