[an error occurred while processing this directive]
simple round-robin for H8S
(«Телесистемы»: Конференция «Микроконтроллеры и их применение»)

миниатюрный аудио-видеорекордер mAVR

Отправлено AK 11 ноября 2002 г. 09:59
В ответ на: Ясненько, но для моих задач маловато. Все равно спасибо. отправлено DASM 11 ноября 2002 г. 09:23

Written for Hitachi C compiler :-)))


/////// header file "RRR.h" ///////

#define STOP_TASK -1 // 0xFFFF - stop task
#define RUN_TASK 0 // 0 - task is active and running
#define MAX_TASKS 4 // max number of tasks
#define TASK_STACK_SIZE 0x80 // number of bytes allocated to each task stack

extern volatile int System_Tick; // this is a 1 ms flag set by timer ISR

// ---------------------------
// --- RTOS initialisation ---
// ---------------------------
// needed in resetprg.c
extern void RTOS_clear_tasks(void); // init tasks table
extern void RTOS_register_task(void (*task_x)(void), int Task_Time);

// --------------------
// --- RTOS service ---
// --------------------
// used by tasks
extern void RTOS_delay(int T); // service for tasks, T - number of ticks
extern void RTOS_wake_up_task(int Task_No, int T); // wake up other task
extern int RTOS_current_task_No(void); // query current task No

// --------------
// --- Kernel ---
// --------------
extern void RTOS_Kernel(void); // RTOS itself, used in resetprg.c;

//////////// C module "RRR.c" ////////////////

#include "RRR.h"

/*************************************************************************
RR_RTOS provides very basic service for tasks. Task can release control
to kernel executing function

void RTOS_delay(int T)

where T - number of ticks (tick=1ms).

RTOS returns control to the task when t ticks are expired, meanwhile
other task will be running. If T=0 then RTOS returns control to the task
ASAP, however, other task will get control before RTOS returns control
to that task. Eg. tasks shall voluntary execute

RTOS_delay(0);

as often as possible, it ensures that other tasks won't be blocked.
Valid t range if from 0 to 0x7FFF, eg delays from 0 to ~0.5 min are available.
Value 0xFFFF (eg -1) has a special meaning. If task releases control
to RTOS by executing

RTOS_delay(-1);

then its tick counter will not be decremented, and it will not get control
back from RTOS. However, other task can wake up the sleeping task executing
function

void RTOS_wake_up_task(int TASK_No, int T)

where Task_No - task to be woken up;
T - number of ticks (tick=1ms) before task runs

Note that RTOS_delay(T) deliberatly stores all H8S registers in stack.
RTOS kernel restores all registers from stack prior to jumping back to that
task. RTOS_delay() can be safely used even if task returns control to RTOS from
inside a function.

**************************************************************************/

// ************************************ //
// //
// Task samples //
// //
// ************************************ //

/*
void task_0(void) // dummy task
{
int var_i;
var_i = 0;
while (1==1)
{
var_i++;
RTOS_delay(0);
var_i--;
RTOS_delay(1);
}
}

void task_12(void) // dummy task
{
int var_j;
var_j = 0;
while (1==1)
{
var_j++;
RTOS_delay(2);
var_j--;
RTOS_delay(1);
}
}
*/

// ************************************ //
// //
// Services for tasks //
// //
// ************************************ //
static struct Task_Descriptor
{
int Tick_Counter; // task tick counter
unsigned long SP; // context - stack pointer
} Descriptor[MAX_TASKS+1] ; // declare N task descriptors
static int Current_Task;
static unsigned long Current_SP;

static volatile unsigned long RTOS_own_SP; // stores RTOS SP while tasks are running
volatile int System_Tick; // this is a flag set by timer ISR

// Note: Other context is not stored because control is passed to/from
// RTOS inside function (RTOS_delay). It means that ER0, ER1 store Task_No
// and t, and they will be discarded anyway, thus it is no need to store them.
// Essential context is already in stack before RTOS_delay is being called,
// because task "outer" variables are volatile

// ***********************************************************************
// store context
// ***********************************************************************
// its no point to waste time storing ER0, ER1 because their values are not
// used outside RTOS_delay() function
#pragma inline_asm(store_context)
static void store_context(void)
{
stm.l (ER2-ER3),@-SP ; // store ER2...ER3
stm.l (ER4-ER6),@-SP ; // store ER4...ER6
}

// ***********************************************************************
// return control to RTOS
// ***********************************************************************
// it is GOTO instruction for H8S
#pragma inline_asm(goto_RTOS)
static void goto_RTOS(void)
{
jmp @L_Back_to_RTOS ; // goto global address (RTOS kernel label)
}

// ***********************************************************************
// get current SP value
// ***********************************************************************
// C cannot do it...
#pragma inline_asm(fetch_SP_to_R0)
static unsigned long fetch_SP_to_R0(void)
{
mov.l ER7,ER0 ; //
adds.l #4,ER0 ; // adjustment, to compensate RTS in fetch_SP()
}
// return it via subroutine to ensure that C compiler hanldes result (eg ER0) correctly
static unsigned long fetch_SP(void)
{
return fetch_SP_to_R0();
}

// ***********************************************************************
// procedure to return to kernel
// ***********************************************************************
// RTOS service
void RTOS_delay(int T)
{
Descriptor[Current_Task].Tick_Counter=T; // store new tick counter value
store_context(); // store registers ER2...ER6 in stack
Descriptor[Current_Task].SP=fetch_SP(); // store current SP value in table
goto_RTOS();
}

// ***********************************************************************
// procedure to wake up other task
// ***********************************************************************
// RTOS service
void RTOS_wake_up_task(int Task_No, int T)
{
Descriptor[Task_No].Tick_Counter=T; // set delay for the specified task
}

// ***********************************************************************
// function to query own task No
// ***********************************************************************
// RTOS service
int RTOS_current_task_No(void)
{
return Current_Task; // Current_Task is not visible outside RRR_Kernel.c
}

// ************************************ //
// //
// Functions used in kernel //
// //
// ************************************ //
// tasks do not need to know about them, they are internal RTOS business

// ***********************************************************************
// push value to SP
// ***********************************************************************
// required when task table initialised
#pragma inline_asm(push_task_entry_point)
static void push_task_entry_point(void (*Task_x)(void))
{
push.l ER0 ; // push function pointer
}

// ***********************************************************************
// assign new value to SP (ER7)
// ***********************************************************************
#pragma inline_asm(write_to_SP)
static void write_to_SP(unsigned long SP_value)
{
mov.l ER0,ER7 ; // write SP_value to ER7 (SP)
}


// ***********************************************************************
// execute RTS
// ***********************************************************************
// to return back to task
#pragma inline_asm(rts)
static void rts(void)
{
rts
}

// ***********************************************************************
// restore context
// ***********************************************************************
#pragma inline_asm(restore_context)
static void restore_context(void)
{
ldm.l @SP+,(ER4-ER6) ; // restore ER4...ER6
ldm.l @SP+,(ER2-ER3) ; // restore ER2...ER3
}

// ***********************************************************************
// Label
// ***********************************************************************
// this global label will be inserted into compiled ASM code
#pragma inline_asm(RTOS_label)
static void RTOS_label(void)
{
L_Back_to_RTOS:
}

// ***********************************************************************
// clear tasks
// ***********************************************************************
// shall be executed once at power-up
void RTOS_clear_tasks(void)
{
for (Current_Task=0; Current_Task<=MAX_TASKS; Current_Task++)
{
Descriptor[Current_Task].Tick_Counter=STOP_TASK; // task sleeps
}
// --- prepare for RTOS_register_task()
Current_Task=0;
Current_SP=fetch_SP() - 0x40; // allot 40h of stack for RTOS
}

// ***********************************************************************
// register task
// ***********************************************************************
// shall be executed once at initialisation
void RTOS_register_task(void (*task_x)(void), int Task_Time)
{
RTOS_own_SP=fetch_SP(); // temp store current SP
Descriptor[Current_Task].Tick_Counter=Task_Time; // set task time
write_to_SP(Current_SP); // set new SP
push_task_entry_point(task_x); // push task entry point
store_context(); // store some boolshit context
Descriptor[Current_Task].SP=fetch_SP(); // finally store SP
Current_SP=Current_SP - TASK_STACK_SIZE; // allot 80h of stack for that task
Current_Task++; // ready to register next task
write_to_SP(RTOS_own_SP); // restore current SP
}

// ************************************ //
// //
// RTOS kernel (task switcher) //
// //
// ************************************ //

// ----------------------
void RTOS_Kernel(void)
{
// ----------------------------------
// --- endless task switcher loop ---
// ----------------------------------
System_Tick=0; // reset tick before loop starts
while (0==0)
{
// ----------------------------------------------------------
// --- check each task and pass control to it if required ---
// ----------------------------------------------------------
for (Current_Task=0; Current_Task<=MAX_TASKS; Current_Task++)
{
if (Descriptor[Current_Task].Tick_Counter==RUN_TASK) // if task active
{
store_context(); // store RTOS context
RTOS_own_SP=fetch_SP(); // temp store current SP
write_to_SP(Descriptor[Current_Task].SP); // set SP for that task
restore_context(); // and restore other registers
rts(); // return to task
// ---------------->
RTOS_label(); // task returns control here
write_to_SP(RTOS_own_SP); // restore own SP
restore_context(); // and restore RTOS context
}
}
// -----------------------------------------------------------
// --- check tick flag and service task timers if required ---
// -----------------------------------------------------------
if (System_Tick != 0) // if timer ISR rised that flag
{
System_Tick=0; // reset the flag
for (Current_Task=0; Current_Task<=MAX_TASKS; Current_Task++)
{
if (Descriptor[Current_Task].Tick_Counter != RUN_TASK) // ignore tasks that already running
{
if (Descriptor[Current_Task].Tick_Counter != STOP_TASK) // ignore tasks that have been killed
Descriptor[Current_Task].Tick_Counter--; // decrement counter
}
}
}
}
}

Составить ответ  |||  Конференция  |||  Архив

Ответы



Перейти к списку ответов  |||  Конференция  |||  Архив  |||  Главная страница  |||  Содержание  |||  Без кадра

E-mail: info@telesys.ru