Skip to content

Commit c42d0d2

Browse files
committed
add avr in library.properties
fix malloc(It will be strengthened as soon as possible), fix interrupt, need clean code prepared sizing loop , remove conflict malloc , insert stack min
1 parent aee3187 commit c42d0d2

File tree

3 files changed

+179
-42
lines changed

3 files changed

+179
-42
lines changed

library.properties

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
name=Scheduler
2-
version=0.4.4
2+
version=0.4.5
33
author=Arduino
44
maintainer=Arduino <[email protected]>
5-
sentence=Allows multiple tasks to run at the same time, without interrupting each other. For Arduino sam and samd architectures only (Due, Zero...).
5+
sentence=Allows multiple tasks to run at the same time, without interrupting each other. For Arduino avr/sam and samd architectures only (Uno, Due, Zero...).
66
paragraph=The Scheduler library enables the Arduino to run multiple functions at the same time. This allows tasks to happen without interrupting each other.</br>This is a cooperative scheduler in that the CPU switches from one task to another. The library includes methods for passing control between tasks.
77
category=Other
88
url=http://www.arduino.cc/en/Reference/Scheduler
9-
architectures=sam,samd
9+
architectures=avr,sam,samd

src/Scheduler.cpp

+157-37
Original file line numberDiff line numberDiff line change
@@ -24,31 +24,119 @@ extern "C" {
2424

2525
#if defined(ARDUINO_ARCH_AVR)
2626
typedef uint8_t reg_t;
27+
28+
#include <stdlib.h>
29+
30+
struct __freelist {
31+
size_t sz;
32+
struct __freelist *nx;
33+
};
34+
35+
uint32_t __mainloopstack = DEFAULT_STACK_SIZE;
36+
37+
void *__poison_malloc(size_t len)
38+
{
39+
extern size_t __malloc_margin;
40+
extern char *__malloc_heap_start;
41+
extern char *__malloc_heap_end;
42+
extern char *__brkval;
43+
extern struct __freelist *__flp;
44+
45+
struct __freelist *fp1, *fp2, *sfp1, *sfp2;
46+
char *cp;
47+
size_t s, avail;
48+
49+
if (len < sizeof(struct __freelist) - sizeof(size_t))
50+
len = sizeof(struct __freelist) - sizeof(size_t);
51+
52+
for (s = 0, fp1 = __flp, fp2 = 0;
53+
fp1;
54+
fp2 = fp1, fp1 = fp1->nx) {
55+
if (fp1->sz < len)
56+
continue;
57+
if (fp1->sz == len) {
58+
if (fp2)
59+
fp2->nx = fp1->nx;
60+
else
61+
__flp = fp1->nx;
62+
return &(fp1->nx);
63+
}
64+
else {
65+
if (s == 0 || fp1->sz < s) {
66+
s = fp1->sz;
67+
sfp1 = fp1;
68+
sfp2 = fp2;
69+
}
70+
}
71+
}
72+
73+
if (s) {
74+
if (s - len < sizeof(struct __freelist)) {
75+
if (sfp2)
76+
sfp2->nx = sfp1->nx;
77+
else
78+
__flp = sfp1->nx;
79+
return &(sfp1->nx);
80+
}
81+
82+
cp = (char *)sfp1;
83+
s -= len;
84+
cp += s;
85+
sfp2 = (struct __freelist *)cp;
86+
sfp2->sz = len;
87+
sfp1->sz = s - sizeof(size_t);
88+
return &(sfp2->nx);
89+
}
90+
91+
if (__brkval == 0)
92+
__brkval = __malloc_heap_start;
93+
cp = __malloc_heap_end;
94+
95+
if (cp == 0)
96+
cp = (char*)(RAMEND + __mainloopstack) - __malloc_margin;
97+
98+
if (cp <= __brkval)
99+
return 0;
100+
101+
avail = cp - __brkval;
102+
103+
if (avail >= len && avail >= len + sizeof(size_t)) {
104+
fp1 = (struct __freelist *)__brkval;
105+
__brkval += len + sizeof(size_t);
106+
fp1->sz = len;
107+
return &(fp1->nx);
108+
}
109+
110+
return 0;
111+
112+
}
113+
114+
27115
#ifdef EIND
28-
#define GET_FAR_ADDRESS(var) ({ \
29-
uint32_t tmp;\
30-
__asm__ __volatile__( \
31-
"ldi %A0, lo8(%1) \n\t" \
32-
"ldi %B0, hi8(%1) \n\t" \
33-
"ldi %C0, hh8(%1) \n\t" \
34-
"clr %D0 \n\t" \
35-
: \
36-
"=d" (tmp) \
37-
: \
38-
"p" (&(var)) \
39-
); \
40-
tmp;\
41-
})
116+
#define GET_FAR_ADDRESS(var) ({ \
117+
uint32_t tmp;\
118+
__asm__ __volatile__( \
119+
"ldi %A0, lo8(%1) \n\t" \
120+
"ldi %B0, hi8(%1) \n\t" \
121+
"ldi %C0, hh8(%1) \n\t" \
122+
"clr %D0 \n\t" \
123+
: \
124+
"=d" (tmp) \
125+
: \
126+
"p" (&(var)) \
127+
); \
128+
tmp;\
129+
})
42130
#endif
43131
#define NUM_REGS 40 // r0/31 + sp(2) + pc(2) + data(2) + ftask(2)
44-
#define SPL_REG 32
45-
#define SPH_REG 33
46-
#define PCL_REG 34
132+
#define PCL_REG 34
47133
#define PCH_REG 35
48134
#define DATAL_REG 36
49135
#define DATAH_REG 37
50136
#define TASKFL_REG 38
51137
#define TASKFH_REG 39
138+
#define SPL_REG 32
139+
#define SPH_REG 33
52140

53141
#define STACK_EM0 0xFFFF
54142
#define STACK_EM1 0xFFFE
@@ -63,7 +151,6 @@ extern "C" {
63151

64152
#define STACK_EM0 0xFFFFFFFF
65153
#define STACK_EM1 0xFFFFFFFE
66-
67154
#endif
68155

69156
typedef struct CoopTask {
@@ -74,6 +161,7 @@ typedef struct CoopTask {
74161
} CoopTask;
75162

76163
static CoopTask *cur = 0;
164+
CoopTask *mainloop = 0;
77165

78166
static CoopTask* __attribute__((noinline)) coopSchedule(char taskDied) {
79167
CoopTask* next = cur->next;
@@ -104,7 +192,8 @@ static void _NAKED_ _NONINLINE_ coopTaskStart(void) {
104192
"movw 30, r4 \n\t"
105193
"ldd r26, Z+34 ;increment PC, next call ret without call ftask(data) \n\t"
106194
"ldd r27, Z+35 \n\t"
107-
"adiw r26, 62 ;offset ret\n\t"
195+
"adiw r26, 60 ;offset ret\n\t"
196+
"adiw r26, 6 ;offset ret\n\t"
108197
"movw r18, r26 \n\t"
109198
"std Z+34, r18 \n\t"
110199
"std Z+35, r19 \n\t"
@@ -119,11 +208,14 @@ static void _NAKED_ _NONINLINE_ coopTaskStart(void) {
119208
"movw r4, r24 ;r25:r24 cur task\n\t"
120209
"movw 30, r4 ;load context \n\t"
121210
"ldd r6, Z+32 ;load stack\n\t"
211+
"in r0, __SREG__ ;safe interrupt\n\t"
212+
"cli \n\t"
122213
"mov r28,r6 \n\t"
123214
"out __SP_L__, r6 \n\t"
124215
"ldd r6, Z+33 \n\t"
125216
"mov r29,r6 \n\t"
126217
"out __SP_H__, r6 \n\t"
218+
"out __SREG__, r0 \n\t"
127219
"ldd r0, Z+0 ;load register \n\t"
128220
"ldd r1, Z+1 \n\t"
129221
"ldd r2, Z+2 \n\t"
@@ -210,6 +302,8 @@ static void _NAKED_ _NONINLINE_ coopDoYield(CoopTask* curTask _UNUSED_) {
210302
"std Z+33, r4 \n\t"
211303
"ldi r24, 0 ;next coop \n\t"
212304
"call coopSchedule \n\t"
305+
"in r0, __SREG__ ;safe interrupt\n\t"
306+
"cli \n\t"
213307
"movw r4, r24 ;load context \n\t"
214308
"movw 30, r4 \n\t"
215309
"ldd r6, Z+32 \n\t"
@@ -221,6 +315,7 @@ static void _NAKED_ _NONINLINE_ coopDoYield(CoopTask* curTask _UNUSED_) {
221315
"ldd r6, Z+34 ;load pc\n\t"
222316
"ldd r7, Z+35 \n\t"
223317
"movw r30, r6 \n\t"
318+
"out __SREG__, r0 \n\t"
224319
"icall ;call coopTaskStart if begin else return after icall \n\t"
225320
"movw r30, r4 ;need reload structure \n\t"
226321
"ldd r0, Z+0 ;load register \n\t"
@@ -346,8 +441,9 @@ static void _NAKED_ _NONINLINE_ coopDoYield(CoopTask* curTask) {
346441

347442
static int coopInit(void) {
348443
CoopTask* task;
349-
444+
350445
task = reinterpret_cast<CoopTask *>(malloc(sizeof(CoopTask)));
446+
351447
if (!task)
352448
return 0;
353449

@@ -356,24 +452,24 @@ static int coopInit(void) {
356452
task->stackPtr = NULL;
357453

358454
#ifdef ARDUINO_ARCH_AVR
455+
mainloop = task;
359456
task->regs[SPL_REG] = 0;
360457
task->regs[SPH_REG] = 0;
361458
#ifdef EIND
362-
uint32_t pf = GET_FAR_ADDRESS(coopTaskStart);
363-
task->regs[PCL_REG] = ((uint16_t)(pf) + 62) & 0xFF;
364-
task->regs[PCH_REG] = (((uint16_t)(pf) + 62) >> 8) & 0xFF;
459+
uint32_t pf = GET_FAR_ADDRESS(coopTaskStart);
460+
task->regs[PCL_REG] = ((uint16_t)(pf) + 66) & 0xFF;
461+
task->regs[PCH_REG] = (((uint16_t)(pf) + 66) >> 8) & 0xFF;
365462
#else
366-
task->regs[PCL_REG] = ((uint16_t)(coopTaskStart) + 62) & 0xFF;
367-
task->regs[PCH_REG] = (((uint16_t)(coopTaskStart) + 62) >> 8) & 0xFF;
463+
task->regs[PCL_REG] = ((uint16_t)(coopTaskStart) + 66) & 0xFF;
464+
task->regs[PCH_REG] = (((uint16_t)(coopTaskStart) + 66) >> 8) & 0xFF;
368465
#endif
369466
task->regs[DATAL_REG] = 0;
370467
task->regs[DATAH_REG] = 0;
371468
task->regs[TASKFL_REG] = 0;
372469
task->regs[TASKFH_REG] = 0;
373470
#endif
374-
471+
375472
cur = task;
376-
377473
return 1;
378474
}
379475

@@ -397,15 +493,16 @@ static int coopSpawn(SchedulerParametricTask taskF, void* taskData, uint32_t sta
397493
task->regs[DATAL_REG] = (uint16_t)(taskData) & 0xFF;
398494
task->regs[DATAH_REG] = ((uint16_t)(taskData) >> 8) & 0xFF;
399495
#ifdef EIND
400-
uint32_t pf = GET_FAR_ADDRESS(coopTaskStart);
401-
task->regs[PCL_REG] = (uint16_t)(pf) & 0xFF;
496+
uint32_t pf = GET_FAR_ADDRESS(coopTaskStart);
497+
task->regs[PCL_REG] = (uint16_t)(pf) & 0xFF;
402498
task->regs[PCH_REG] = ((uint16_t)(pf) >> 8) & 0xFF;
403499
#else
404500
task->regs[PCL_REG] = (uint16_t)(coopTaskStart) & 0xFF;
405501
task->regs[PCH_REG] = ((uint16_t)(coopTaskStart) >> 8) & 0xFF;
406502
#endif
407503
task->regs[SPL_REG] = (uint16_t)(stack + stackSz - 1) & 0xFF;
408-
task->regs[SPH_REG] = ((uint16_t)(stack + stackSz - 1) >> 8) & 0xFF;
504+
task->regs[SPH_REG] = ((uint16_t)(stack + stackSz - 1 ) >> 8) & 0xFF;
505+
409506

410507
#elif defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD)
411508
task->regs[TASKF_REG] = (uint32_t) taskF;
@@ -434,6 +531,27 @@ void yield(void) {
434531
coopDoYield(cur);
435532
}
436533

534+
#if defined(ARDUINO_ARCH_AVR)
535+
536+
void *__scheduler_malloc(size_t len)
537+
{
538+
extern int __heap_start, *__brkval;
539+
int v = (__brkval == NULL) ? __heap_start : (int)(__brkval);
540+
char* c[5];
541+
if ( (int)(c) < v )
542+
{
543+
return __poison_malloc(len);
544+
}
545+
546+
#pragma pop_macro("malloc")
547+
return malloc(len);
548+
#pragma push_macro("malloc")
549+
#undef malloc
550+
#define malloc __scheduler_malloc
551+
}
552+
553+
#endif
554+
437555
}; // extern "C"
438556

439557
SchedulerClass::SchedulerClass() {
@@ -450,27 +568,29 @@ static void startLoopHelper(void *taskData) {
450568

451569
void SchedulerClass::startLoop(SchedulerTask task, stacksz_t stackSize)
452570
{
571+
if ( stackSize < DEFAULT_MIN_STACK_SIZE)
572+
stackSize = DEFAULT_MIN_STACK_SIZE;
453573
coopSpawn(startLoopHelper, reinterpret_cast<void *>(task), stackSize);
454574
}
455575

456576
static void startTaskHelper(void *taskData) {
457577
SchedulerTask task = reinterpret_cast<SchedulerTask>(taskData);
458578
task();
459-
#if defined(ARDUINO_ARCH_AVR)
460-
yield();
579+
#ifdef ARDUINO_ARCH_AVR
580+
yield();
461581
#endif
462582
}
463583

464584
void SchedulerClass::start(SchedulerTask task, stacksz_t stackSize) {
585+
if ( stackSize < DEFAULT_MIN_STACK_SIZE)
586+
stackSize = DEFAULT_MIN_STACK_SIZE;
465587
coopSpawn(startTaskHelper, reinterpret_cast<void *>(task), stackSize);
466588
}
467589

468590
void SchedulerClass::start(SchedulerParametricTask task, void *taskData, stacksz_t stackSize) {
469-
coopSpawn(task, taskData, stackSize);
591+
if ( stackSize < DEFAULT_MIN_STACK_SIZE)
592+
stackSize = DEFAULT_MIN_STACK_SIZE;
593+
coopSpawn(task, taskData, stackSize);
470594
}
471595

472596
SchedulerClass Scheduler;
473-
474-
#undef _NONINLINE_
475-
#undef _NOKED_
476-
#undef _UNUSED_

src/Scheduler.h

+19-2
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,26 @@
1919

2020
#include <Arduino.h>
2121

22+
#define DEFAULT_MIN_STACK_SIZE 80
23+
2224
#if defined(ARDUINO_ARCH_AVR)
23-
typedef uint16_t stacksz_t;
25+
#ifdef malloc
26+
#pragma push_macro("malloc")
27+
#undef malloc
28+
#else
29+
#define malloc malloc
30+
#pragma push_macro("malloc")
31+
#undef malloc
32+
#endif
33+
34+
#define malloc __scheduler_malloc
2435

36+
typedef uint16_t stacksz_t;
37+
2538
#if ((RAMEND - RAMSTART) < 1000)
2639
#pragma GCC error "board is not supported"
2740
//invoche a real fatal error
28-
#include "board is not supported"
41+
#include "board is not supported"
2942
#elif ((RAMEND - RAMSTART) < 2000)
3043
#define DEFAULT_STACK_SIZE 200
3144
#elif ((RAMEND - RAMSTART) < 3000)
@@ -45,6 +58,10 @@
4558
extern "C" {
4659
typedef void (*SchedulerTask)(void);
4760
typedef void (*SchedulerParametricTask)(void *);
61+
62+
#if defined(ARDUINO_ARCH_AVR)
63+
void *__scheduler_malloc(size_t len);
64+
#endif
4865
}
4966

5067
class SchedulerClass {

0 commit comments

Comments
 (0)