개인적으로 개발하고 있는 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의 경우는 프로그램 실행 시 문제가 발생하지 않습니다.