We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Hello all, If you are interested, I am working on a new personal project - an ARM9 scheduler ("Sand Storm", but the name is still volatile. It will inherit a lot from sourceforge.net/.../, however it will of course run on STR7/9 variants instead). It is still a rudimentary implementation, which I made for demonstration purposes only.
we begin with this declaration:
typedef struct { int32u context[17] ; // buffer for all processor registers int8u id ; task_state status ; int8u priority ; // task priority } t_tcb ;
(tcb = task control block).
assuming 3 tasks are run, the following definitions are made:
t_tcb g_task1tcb, g_task2tcb, g_task3tcb, *g_tasks_tcb[] = {&g_task1tcb, &g_task2tcb, &g_task3tcb} ;
and
#define TASK_STACK_SIZE_NORMAL 0x100 int32u g_current_task_index = 0, g_current_task_index_tcb_index = 0, g_next_task_ptr = 0, g_current_task_ptr = 0, lp_task1_stack[TASK_STACK_SIZE_NORMAL], lp_task2_stack[TASK_STACK_SIZE_NORMAL], lp_task3_stack[TASK_STACK_SIZE_NORMAL] ;
each task needs to be configured prior to running, like this:
void tcb_setup(t_tcb *const ap_tcb, task_ptr ap_task, int32u *ap_stack, int16u a_stack_size) { int32u *l_tcb_word = &ap_tcb->context[16], *lp_stack = ap_stack, l_value ; // IRQ ISR return address (ending of tcb) // the IRQ ISR must (according to the ARM architecture) decrement 4 from each // return address. so the return address of each IRQ ISR must be incremented by 4. *(l_tcb_word--) = (int32u)ap_task + 4 ; // SPSR *(l_tcb_word--) = (int32u)0x50 ; // R14 - internal task return address *(l_tcb_word--) = (int32u)ap_task ; // R13 - stack top *(l_tcb_word--) = (int32u)ap_stack ; // R12 *(l_tcb_word--) = (int32u)0x12012012 ; // R11 *(l_tcb_word--) = (int32u)0x11011011 ; // R10 *(l_tcb_word--) = (int32u)0x10101010 ; // R9 *(l_tcb_word--) = (int32u)0x99999999 ; // R8 *(l_tcb_word--) = (int32u)0x88888888 ; // R7 *(l_tcb_word--) = (int32u)0x77777777 ; // R6 *(l_tcb_word--) = (int32u)0x66666666 ; // R5 *(l_tcb_word--) = (int32u)0x55555555 ; // R4 *(l_tcb_word--) = (int32u)0x44444444 ; // R3 *(l_tcb_word--) = (int32u)0x33333333 ; // R2 *(l_tcb_word--) = (int32u)0x22222222 ; // R1 *(l_tcb_word--) = (int32u)0x11111111 ; // R0 (beginning of tcb) *(l_tcb_word--) = (int32u)0x00000000 ; // fill user provided stack with predicted, handy from debugging l_value = 0x1111 ; while (a_stack_size-- > 0) { *(lp_stack++) = l_value ; l_value <<= 1 ; if (l_value >= 0x1111000) { l_value = 0x1111 ; } } }
tcb_setup(&g_task1tcb, &task1, lp_task1_stack, TASK_STACK_SIZE_NORMAL) ; tcb_setup(&g_task2tcb, &task2, lp_task2_stack, TASK_STACK_SIZE_NORMAL) ; tcb_setup(&g_task3tcb, &task3, lp_task3_stack, TASK_STACK_SIZE_NORMAL) ;
where the task functions are defined the following way: (only task1 is demonstrated):
void task1(void) { while(1) { } }
#pragma arm section zidata = "non_init_2" __attribute__ ((zero_init)) int32u g_irq_stack_base ; #pragma arm section zidata
The variable 'g_irq_stack_base' is placed in a section that is not initialized to zero upon startup. That is required because after the startup file sets the variable (during stack setup),
;*********************************************************** ; required for restoration of IRQ stack after context switch IMPORT g_irq_stack_base LDR R1, =g_irq_stack_base STR R0, [R1] ;***********************************************************
that branch to '__main' will reset it. Notice that this code is developed to be build with a RealView compiler. I have not made a GNU variant yet.
Greetings,
Tamir
Please note that 'scheduler_select_next_task' is a function that selects the next task to be run. I will not post it here as it has no value for this thread. The simplified logic at the original post can be used instead.