/*----------------------------------------------------------------------------
* A R T X - K e r n e l
*----------------------------------------------------------------------------
* Name: ARTX_CONFIG.C
* Purpose: Configuration of ARTX Kernel for Atmel AT91SAM7S
* Rev.: V1.10 / 11-jul-2005
*----------------------------------------------------------------------------
* This code is part of the ARTX-ARM kernel package of Keil Software.
* Copyright (c) 2004-2005 Keil Software. All rights reserved.
*---------------------------------------------------------------------------*/
#pragma INTERWORK
#define NOFRAME __arm __task
#include <AT91SAM7S64.H>
#include <ARTX_Config.h> /* ARTX 用户配置头文件*/
/*----------------------------------------------------------------------------
* ARTX User configuration part BEGIN
*---------------------------------------------------------------------------*/
//-------- <<< Use Configuration Wizard in Context Menu >>> -----------------
//
// <h>任务定义
// ===================
//
// OS_TASKCNT:定义当前运行的任务数<0-250>
// Can be less than the number of defined tasks or more if
// multi instances of tasks will run. This define is used
// to calculate the the memory block size that is reserved
// for fixed memory block management.
// 默认任务数: 6
#define OS_TASKCNT 6
// OS_PRIVCNT: 定义使用用户堆栈区的任务数<0-250>
// 某些需要比OS_STKSIZE更大的堆栈区的任务.
// 在这种情况下内存空间就需要用户自己来分配而不是用系统分配
// 默认数: 0
#define OS_PRIVCNT 0
// OS_STKSIZE: 系统任务堆栈大小(字节byte) <20-4096:4><#/4>
// This stack is used for task''s stack and context switch
// <i> for registers and system stack storage.
// 默认值: 200
#define OS_STKSIZE 50
// OS_TIMERCNT: 用户定时器数的定义<0-250>
// Define max. number of user timers running. They act as
// a watchdog timer counting down on each system clock tick.
// On timeout the user provided function is called.
// 默认值: 0 (User timers disabled)
#define OS_TIMERCNT 0
// </h>
// <h>系统时钟配置
// =============================
// OS_TIMER: ARTX 内核时钟<0=> PIT
// 定义ARM定时器作为系统节拍时钟
// 默认值: PIT
#define OS_TIMER 0
// <o>OS_CLOCK: 定时时钟的值[Hz] <1-1000000000>
//
// <i> Default: 3000000 (3MHz at 48MHz MCLK and prescaler by 16)
#define OS_CLOCK 3000000
// <o>OS_TICK: 定时器节拍值[us] <1-1000000>
// 为所选定的定时器设定节拍值
// 默认值: 10000 (10ms)
#define OS_TICK 10000
//
// Round-Robin Task switching
#define OS_ROBIN 1
// OS_ROBINTOUT: Round-Robin Timeout in system ticks <1-1000>
// 这是一个分配给正在运行的任务的时间片
// When this expires, round robin task switch takes place.
// Default: 5
#define OS_ROBINTOUT 5
// </e>
//------------- <<< end of configuration section >>> -----------------------
/*----------------------------------------------------------------------------
* ARTX User configuration part END
*---------------------------------------------------------------------------*/
#if (OS_TIMER == 0) /* PIT */
#define OS_TIM (1 << AT91C_ID_SYS) /* Interrupt Mask */
#define OS_TRV ((DWORD)(((double)OS_CLOCK*(double)OS_TICK)/1E6)-1)
#define OS_TVAL (*AT91C_PITC_PIIR & 0x000FFFFF) /* Timer Value */
#define OS_TOVF (*AT91C_PITC_PISR & 1) /* Overflow Flag */
#define OS_TREL() ; /* Timer Reload */
#define OS_TFIRQ() *AT91C_AIC_ISCR = OS_TIM; /* Force Interrupt */
#define OS_TIACK() *AT91C_AIC_EOICR = *AT91C_PITC_PIVR; \
*AT91C_AIC_ICCR = OS_TIM; /* Interrupt Ack */
#define OS_TINIT() *AT91C_PITC_PIMR = OS_TRV /* Initialization */ \
AT91C_PITC_PITIEN AT91C_PITC_PITEN; \
*(AT91C_AIC_SPU) = (DWORD)os_def_interrupt; \
*(AT91C_AIC_SVR + AT91C_ID_SYS) = \
(DWORD)os_clock_interrupt; \
*(AT91C_AIC_SMR + AT91C_ID_SYS) = \
AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED 0; \
*(AT91C_AIC_IECR) = OS_TIM;
#else
#error OS_TIMER invalid
#endif
#define OS_LOCK() *AT91C_AIC_IDCR = OS_TIM; /* Lock */
#define OS_UNLOCK() *AT91C_AIC_IECR = OS_TIM; /* Unlock */
/* WARNING ! Do not use IDLE mode if you are using a JTAG interface */
/* for debugging your application. */
#define _idle_() *AT91C_PMC_SCDR = 1;
#define INITIAL_CPSR 0x40000010
/*----------------------------------------------------------------------------
* Global Variables全局变量
*---------------------------------------------------------------------------*/
extern P_TCB os_runtask;
extern struct OS_XCB os_rdy;
extern struct OS_TCB os_clock_TCB;
extern WORD os_time;
WORD const os_maxtaskrun = OS_TASKCNT;
/* Export following defines to uVision debugger. */
WORD const os_stacksize = OS_STKSIZE * 4;
DWORD const os_clockrate = (DWORD)((double)(OS_TRV+1)*1E6/(double)OS_CLOCK);
DWORD const os_timernum = (OS_TIMER << 16) OS_TIMERCNT;
DWORD const os_rrobin = (OS_ROBIN << 16) OS_ROBINTOUT;
/*----------------------------------------------------------------------------
* Local Variables局部变量
*---------------------------------------------------------------------------*/
/* Memory pool for TCB allocation */
static DWORD m_tcb[(sizeof(struct OS_TCB) * OS_TASKCNT)/4 + 3];
/* Memory pool for System stack allocation. Need to allocate 2 additional */
/* entries for ''os_clock_demon()'' and ''os_idle_demon()''. */
static DWORD m_stk[OS_STKSIZE * (OS_TASKCNT-OS_PRIVCNT+2) + 3];
/* An array of Active task pointers. */
P_TCB os_active_TCB[OS_TASKCNT];
#if (OS_ROBIN == 1)
static WORD os_robin_time;
static P_TCB os_tsk_robin;
#endif
#if (OS_TIMERCNT != 0)
/* Memory pool for User Timer allocation */
static DWORD m_tmr[(sizeof(struct OS_TMR) * OS_TIMERCNT)/4 + 3];
#endif
/*----------------------------------------------------------------------------
* Global Functions全局函数
*---------------------------------------------------------------------------*/
/*--------------------------- os_idle_demon ---------------------------------*/
void os_idle_demon (void) __task {
/* The idle demon is a system task. It is running when no other task is */
/* ready to run (idle situation). It must not terminate. Therefore it */
/* should contain at least an endless loop. */
for (;;) {
/* HERE: include here optional user code to be executed when no task runs.*/
}
} /* end of os_idle_demon */
/*--------------------------- os_tmr_call -----------------------------------*/
void os_tmr_call (WORD info) {
/* This function is called when the user timer has expired. */
/* Parameter "info" is the parameter defined when the timer was created. */
/* HERE: include here optional user code to be executed on timeout. */
info = info;
} /* end of os_tmr_call */
/*--------------------------- os_clock_interrupt ----------------------------*/
void os_clock_interrupt (void) NOFRAME {
/* Do task switch to clock demon: entered upon a clock interrupt. */
__asm {
STMDB SP!,{R0-R1} ; Save Full Context
STMDB SP,{SP}^ ; User SP
LDMDB SP,{R0}
MRS R1,SPSR ; User CPSR
SUB LR,LR,#0x4
STMDB R0!,{R1,LR} ; Push PC, CPSR
STMDB R0,{LR}^ ; Push User LR
SUB R0,R0,#0x4 ; Write back problem !!
STMDB R0!,{R2-R12} ; Push R12-R2
LDMIA SP!,{R2-R3}
STMDB R0!,{R2-R3} ; Push R1-R0
LDR R1,=os_runtask ; os_runtask
LDR R1,[R1,#0x0] ; os_runtask
STR R0,[R1,#TCB_TSTACK] ; os_runtask->tsk_stack
}
OS_TIACK();
tsk_lock ();
os_runtask->full_ctx = TRUE;
os_runtask->state = READY;
os_put_rdy_first (os_runtask);
os_runtask = &os_clock_TCB;
os_clock_TCB.state = RUNNING;
__asm {
LDR R0,=os_runtask ; os_runtask
LDR R0,[R0,#0x0] ; os_runtask
LDR R0,[R0,#TCB_TSTACK] ; os_runtask->tsk_stack
LDMIA R0!,{R4-R8,R12}
MSR SPSR_cxsf,R8
STMDB SP,{R0} ; Set User SP
LDMDB SP,{SP}^
MOVS PC,R12 ; RETI
}
} /* end of os_clock_interrupt */
/*--------------------------- os_def_interrupt ------------------------------*/
void os_def_interrupt (void) __irq {
/* Default Interrupt Function: may be called when timer ISR is disabled */
}
/*--------------------------- os_tmr_init -----------------------------------*/
void os_tmr_init (void) {
/* Initialize hardware timer as system tick timer. This function is */
/* called at the system startup. */
OS_TINIT();
#if (OS_ROBIN == 1)
os_robin_time = OS_ROBINTOUT;
#endif
} /* end of os_tmr_init */
/*--------------------------- os_tmr_reload ---------------------------------*/
void os_tmr_reload (void) {
/* Reload system timer for next period if a timer requires reload. */
OS_TREL();
} /* end of os_tmr_reload */
/*--------------------------- os_tmr_force_irq ------------------------------*/
void os_tmr_force_irq (void) {
/* Force a timer interrupt. */
OS_TFIRQ();
} /* end of os_tmr_force_irq */
/*--------------------------- os_tmr_inspect_cnt ----------------------------*/
DWORD os_tmr_inspect_cnt (void) {
/* Inspect current value of rtx timer. */
return (OS_TVAL);
} /* end of os_tmr_inspect_cnt */
/*--------------------------- os_tmr_inspect_ovf ----------------------------*/
BOOL os_tmr_inspect_ovf (void) {
/* Inspect current state of timer overflow flag. */
return (OS_TOVF);
} /* end of os_tmr_inspect_ovf */
/*--------------------------- tsk_lock --------------------------------------*/
void tsk_lock (void) {
/* Lock out tasks: prevents task switching by locking out scheduler */
/* activation on interrupt. . */
OS_LOCK();
} /* end of tsk_lock */
/*--------------------------- tsk_unlock ------------------------------------*/
void tsk_unlock (void) {
/* Enable AR System Tick Timer Interrupts. */
OS_UNLOCK();
} /* end of tsk_unlock */
/*--------------------------- os_init_mem -----------------------------------*/
void os_init_mem (void) {
WORD i;
for (i = 0; i < OS_TASKCNT; i++) {
os_active_TCB[i] = NULL;
}
_init_box (&m_tcb, sizeof(m_tcb), sizeof(struct OS_TCB));
_init_box (&m_stk, sizeof(m_stk), OS_STKSIZE*4);
#if (OS_TIMERCNT != 0)
_init_box (&m_tmr, sizeof(m_tmr), sizeof(struct OS_TMR));
#endif
} /* end of os_init_mem */
/*--------------------------- os_alloc_TCB ----------------------------------*/
P_TCB os_alloc_TCB () {
return (_alloc_box (m_tcb));
} /* end of os_alloc_TCB */
/*--------------------------- os_free_TCB -----------------------------------*/
void os_free_TCB (P_TCB p_TCB) {
/* Free allocated memory resources for the task "p_TCB" */
_free_box (m_stk, p_TCB->stack);
_free_box (m_tcb, p_TCB);
} /* end of os_free_TCB */
/*--------------------------- os_alloc_TMR ----------------------------------*/
P_TMR os_alloc_TMR () {
#if (OS_TIMERCNT != 0)
return (_alloc_box (m_tmr));
#else
return (NULL);
#endif
} /* end of os_alloc_TMR */
/*--------------------------- os_free_TMR -----------------------------------*/
void os_free_TMR (P_TMR timer) {
/* Free allocated memory resources for user timer ''timer'' */
#if (OS_TIMERCNT != 0)
_free_box (m_tmr, timer);
#else
timer = timer;
#endif
} /* end of os_free_TMR */
/*--------------------------- os_init_context -------------------------------*/
void os_init_context (P_TCB p_TCB, BYTE priority,
FUNCP task_body, BYTE full_context) {
/* Prepare TCB and saved context for a first time start of a task */
/* "p_TCB" points to TCB to be initialised. "priority" indicates desired */
/* execution priority. "task_body" is the start address of the task. */
/* "full_context" identifies context type. */
DWORD *stk,i;
/* Initialise general part of TCB */
p_TCB->cb_type = TCB;
p_TCB->state = READY;
p_TCB->prio = priority;
p_TCB->p_lnk = NULL;
p_TCB->p_rlnk = NULL;
p_TCB->p_dlnk = NULL;
p_TCB->p_blnk = NULL;
p_TCB->delta_time = 0;
p_TCB->interval_time = 0;
p_TCB->events = 0;
p_TCB->waits = 0;
/* Initialise ARM specific part of TCB */
p_TCB->full_ctx = full_context;
/* Prepare a complete interrupt frame for first task start */
if (p_TCB->priv_stack != 0) {
/* User has provided a memory space for the stack. */
stk = &p_TCB->stack[p_TCB->priv_stack>>2];
}
else {
/* Allocate the memory space for the stack. */
p_TCB->stack = _alloc_box (m_stk);
/* Write to the top of stack. */
stk = &p_TCB->stack[OS_STKSIZE];
}
/* Initial PC and default CPSR */
*--stk = (DWORD)task_body;
i = INITIAL_CPSR;
/* If a task in THUMB mode, set T-bit. */
if ((DWORD)task_body & 1) {
i = 0x00000020;
}
*--stk = i;
/* Write initial registers. */
for (i = full_context ? 13 : 4; i; i--) {
*--stk = 0;
}
/* For "full_context" assign a void pointer to R0. */
if (full_context) {
*--stk = (DWORD)p_TCB->p_msg;
}
/* Initial Task stack pointer. */
p_TCB->tsk_stack = (DWORD)stk;
/* Task entry point. */
p_TCB->ptask = task_body;
} /* end of os_init_context */
/*--------------------------- os_set_env ------------------------------------*/
void os_set_env (P_TCB p_TCB) {
/* Fix up runtime environment to fit idle task. It is called after the */
/* idle task TCB initialization. "p_TCB" identifies the TCB to be used. */
p_TCB = p_TCB;
__asm {
LDR R0,[R0,#TCB_TSTACK] ; p_TCB in R0
MOV SP,R0
ADD SP,SP,#24 ; ignore default context
}
} /* end of os_set_env */
/*--------------------------- os_switch_tasks -------------------------------*/
void os_switch_tasks (P_TCB p_new) __swi (0) {
/* Switch to next task (identified by "p_new"). Saving old and restoring */
/* new context is written in assembly (module: Swi_ARTX.s) */
os_runtask->full_ctx = FALSE;
os_runtask = p_new;
p_new->state = RUNNING;
#if (OS_ROBIN == 1)
os_tsk_robin = p_new;
#endif
/* Tsk_Unlock */
OS_UNLOCK();
} /* end of os_switch_tasks */
/*--------------------------- os_chk_robin ----------------------------------*/
void os_chk_robin (void) {
/* Check if Round Robin timeout expired and switch to the next ready task.*/
/* This function is called from the "os_clock_demon()" task scheduler. */
#if (OS_ROBIN == 1)
P_TCB p_new;
if (os_rdy.p_lnk != os_tsk_robin) {
os_robin_time = os_time + OS_ROBINTOUT;
return;
}
if (os_robin_time == os_time) {
/* Round Robin timeout has expired. */
os_robin_time += OS_ROBINTOUT;
p_new = os_get_first (&os_rdy);
os_put_prio ((P_XCB)&os_rdy, p_new);
}
#endif
} /* end of os_chk_robin */
/*----------------------------------------------------------------------------
* end of file
*---------------------------------------------------------------------------*/
边理解边改