개인적으로 개발하고 있는 multitasking이 되는 micro kernel입니다.

Target board는 아무래도 제가 개발에 참여한 HMS39C7092 Embedded Flash ARM MCU를
이용한 Evaluation Board입니다.
익숙한데다 적용이 편하기 때문에 쓰던 것을 그냥 썼습니다.

http://www.wavyvision.co.kr/src/products/products_detail.php?product_category_id=16&product_mst_id=0016_00001

다음에는 CorTex-M3용으로 코딩할 예정입니다.

일단 어느정도 코딩이 정리가 되었습니다.

기능적으로 2개의 thread (엄밀하게는 1개의 메인과 1개의 thread)를 돌리는 데까지는 되는군요.
task switching과 delay 함수까지 구현이 되어 있습니다.
(다만 delay의 경우 정확한 시간은 아니고 task turn count라고 봐야겠지요.)
스펙상으로는 메모리가 허용하는 한, 255개의 task까지 동시 실행가능합니다.
task interval은 timer를 정의하는데에 따라 다릅니다만,
현재 테스트 상황에서는 100us tick timer를 사용하였습니다.

task switching의 main 이 되는 tasksw.s는 아래와 같습니다.
최소한으로 하기 위해서 나름대로 기본기능만 넣었습니다.
kernel부분만 하면 100라인정도 밖에 되지 않습니다.

//	tasksw.s
;//========================================================;//		piOS Real-time Multitasking Operating System;//		micro kerenl source version 0.1.3;//		Programmed by lebych on 1 March 2010;//		All right reserved;//========================================================TASK_MODE		EQU		0x0000001F		;//USER MODENUMBER_OF_TASKS	EQU		2TASKSTACK_SIZE	EQU		(128)TASKSTACK_SHIFT	EQU		7;// * Stack Structure;//--------------------------------------------------------;//	  index	   offset 	type;//--------------------------------------------------------;//		0		0x00	id;//		1		0x04	status;//		2		0x08	CPSR;//		3		0x0c	R0;//		4		0x10	R1;//		5		0x14	R2;//		6		0x18	R3;//		7		0x1c	R4;//		8		0x20	R5 ;//		9		0x24	R6;//		10		0x28	R7;//		11		0x2c	R8;//		12		0x30	R9 ;//		13		0x34	R10;//		14		0x38	R11;//		15		0x3c	R12;//		16		0x40	R13;//		17		0x44	R14;//		18		0x48	R15;//--------------------------------------------------------;//		19		0x4c	;//		20		0x50	;//		21		0x54	;//		22		0x58	;//		23		0x5c	;//		24		0x60	;//		25		0x64	;//		26		0x68	;//		27		0x6c	;//		28		0x70	;//		29		0x74	;//		30		0x78	;//		31		0x7c	;//--------------------------------------------------------			EXPORT	task_init			EXPORT	task_switcher			EXPORT	task_interrupt			EXPORT	task_register			EXPORT	task_sleep			;--------------------------			;	Task Switcher			;	Called from FIQ			;	Switching Time is About 2us			;--------------------------task_interrupt			task_switcher		msr	CPSR_cxsf,#0xD1							ldr	r8,=TIMER_base			ldr	r8,[r8,#TSR0]							mrs	r9,SPSR				;//store previous task stack			and	r10,r9,#0x1F			cmp	r10,#0x1F			bne	jmppp							ldr	r8,_task_ptr			add	r8,r8,#2*4			stmia	r8!,{r9}			stmia	r8,{r0-r14}^			add	r8,r8,#15*4			sub	lr,lr,#4 			stmia	r8!,{lr}			add	r8,r8,#13*4			adr	r12,_task_stack_endnext_task_loop		cmp	r8,r12			adrge	r8,_task_stack			str	r8,_task_ptr			ldmia	r8!,{r9,r10,r11}		;//read ID and STATUS, SPSR			tst	r9,#0x40			beq	skip_to_next			cmp	r10,#0			bgt	skip_to_next_decrement				next_task_run		;//restore next task stack			msr	SPSR_cxsf,r11			ldmia	r8!,{r0-r14}^		;//restore User/System Mode Registers			ldmia	r8 ,{pc}^			;//SPSR->CPSR and Jump to PCskip_to_next_decrement			sub	r10,r10,#1			str	r10,[r8,#-8]			;//store decreased value of statusskip_to_next		add	r8,r8,#(TASKSTACK_SIZE-3*4)	;//Task except for ID and Status			b	next_task_loopjmppp							subs	pc,lr,#4							;--------------------------			;	Set Task Sleep Tick			;--------------------------task_sleep							stmfd	sp!,{r2,lr}			swi	0x0001			adr	r2,_task_stack			add	r2,r2,r0, LSL #TASKSTACK_SHIFT			str	r1,[r2,#4]				;//store into status			swi	0x0002				task_sleep_loop		ldr	r1,[r2,#4]			cmp	r1,#0			bne	task_sleep_loop							ldmfd	sp!,{r2,pc}							;--------------------------			;	Initialize Task Buffer			;--------------------------task_init		stmfd	sp!,{r0-r3,lr}			mov	r0,#0			adr	r1,_task_stack			mov	r2,#NUMBER_OF_TASKS*TASKSTACK_SIZEtask_init_loop		str	r0,[r1],#4			subs	r2,r2,#4			bgt	task_init_loop			mov	r0,#0			mov	r1,#0x40			mov	r2,lr			add	r3,sp,#4			bl	task_register			ldmfd	sp!,{r0-r3,pc}							;--------------------------			;	Register a Task			;--------------------------task_register		;//r0=task number, r1=task id, r2=task address, r3=task stack pointer			stmfd	sp!,{r4-r7,lr}			ldr	r5,=_task_stack			add	r5,r5,r0,LSL #TASKSTACK_SHIFT	;//R4 = &_task_stack[n]			stmia	r5!,{r1}		;//TASK ID			mov	r6,#0			stmia	r5!,{r6}		;//TASK STATUS			mov	r6,#TASK_MODE	;//USER MODE			stmia	r5!,{r6}		;//SPSR			mov	r6,#0			stmia	r5!,{r6}		;//R0			stmia	r5!,{r6}		;//R1			stmia	r5!,{r6}		;//R2			stmia	r5!,{r6}		;//R3			stmia	r5!,{r6}		;//R4			stmia	r5!,{r6}		;//R5			stmia	r5!,{r6}		;//R6			stmia	r5!,{r6}		;//R7			stmia	r5!,{r6}		;//R8			stmia	r5!,{r6}		;//R9			stmia	r5!,{r6}		;//R10			stmia	r5!,{r6}		;//R11			stmia	r5!,{r6}		;//R12			stmia	r5!,{r3}		;//R13: Stack Pointer			stmia	r5!,{r6}		;//R14: Link Register			stmia	r5!,{r2}		;//PC											ldmfd	sp!,{r4-r7,pc}												_task_ptr		DCD	_task_stack_task_stack		%	NUMBER_OF_TASKS*TASKSTACK_SIZE	;r0~r15,SPSR_usr_task_stack_end						END				


그리고 task를 등록 해주고 실행하는 main부분은 아래와 같습니다.
task1 (main) 부분에서는 uart로 문자를 입력/출력 해주고,
task2 에서는 LED를 주기적으로 깜박거립니다.


//	pios.c (main)
#include "def.h"#include "7092.h"#include "console.h"#include "timer.h"void	task_init(void);void	system_init(void){	FMWR =0x0005;	PAMR =0x2aab;	PBMR =0x0000;	P1MR =0x0000;	P2MR =0x0000;	P3MR =0x0000;	P4MR =0x0000;	P5MR =0x0000;	P6MR =0x0000;	P7MR =0x0000;	P8MR =0x0000;	P9MR =0x0000;		PADDR=0x00;	PADR =0xFF;	PBDDR=0x00;	PBDR =0xFF;	P1DDR=0x00;	P1DR =0x00;	P2DDR=0x00;	P2DR =0x00;	P5DDR=0x00;	P5DR =0x00;	P3DDR=0x00;	P3DR =0x00;	P4DDR=0xFF;	P4DR =0x00;	P6DDR=0x00;	P6DR =0x00;	P7DDR=0xC0;	P7DR =0x00;	P8DDR=0x00;	P8DR =0xFF;		BCR0 =0x0004;	BCR1 =0x0104;	BCR2 =0x0104;	BCR3 =0x0104;	BCR4 =0x0104;	BCR5 =0x0104;	BCR6 =0x0104;	BCR7 =0x0104;		MEMCR = 0x03;		// ISRAM remap on page-0	GMR = ~(IB_UART0+IB_UART1+IB_TIMER_ALL+IB_WDT /*+IB_IRQ0+IB_IRQ1+IB_IRQ2+ IB_IRQ4+IB_IRQ5 +IB_IRQ6+IB_IRQ7*/);	IDR = IB_TIMER0;	TMR = IB_UART0+IB_UART1+IB_TIMER_ALL+IB_WDT+IB_ADC;	TPR = IB_UART0+IB_UART1+IB_TIMER_ALL+IB_WDT+IB_ADC +IB_IRQ4+IB_IRQ5 +IB_IRQ6+IB_IRQ7;	FMR = 0;	IMR =  0;	ISCR = ~0;	UCLKDR=9;	UCLKCR=1;}unsigned char	task2_stack[256];void	task2(void){	while(1) {		task_sleep(1,10);//		sleep(10);//		cputs(".");		P7DR^=0x20;	}}int	_main(void){	int		ch;	system_init();	csetport(0);	cinit();	timer_init();	task_init();	task_register(1,0x41,task2,task2_stack+sizeof(task2_stack));	EI();		cprintf("*piOS test program!!*\r\n");		while(1) {		ch=cgetchar();		if(ch>=0) {			if(ch=='\r')				cprintf("\n");			cprintf("%c",ch);				}	}	return 0;}

일단은 기본적인 동작상으로는 문제가 없어 보입니다
다음에는 Thumb-2 Instruction으로 코딩해야겠습니다.

p.s. ADS 1.2 환경에서 J-Link V7으로 외부 16비트 SRAM으로 돌려서 테스트하고 있습니다.
가끔가다 Data Abort나 Prefetch Abort가 나길래 뭔가 했더니만,
HMS39C7092의 버그와 관련된 것이더군요.
일단 7092는 외부 16비트 메모리에서는 프로그램이 실행되지 않습니다.
외부 16비트 메모리는 데이터로만 억세스 가능하고 프로그램은 실행되지 않도록 코딩이 되어 있습니다.
7092 개발 당시 실수로 인해, Data Access만 되고, 연속적은 address에 대해서는 일부 코드가 리마크 되어 버려서
처리가 안되는 경우가 생깁니다. 대충 실행은 되는데, 가끔가다 엉뚱한 값을 fetch해버립니다.
하여간 7092로 외부 16비트 SRAM으로 프로그램을 올려서 개발할 경우 주의를 요합니다.
하지만 8비트 SRAM의 경우는 프로그램 실행 시 문제가 발생하지 않습니다.

Posted by 벅스바니
,