PXA255 로 포팅된 MicroC/OS-II Realtime Kernel 을 분석했다. 여기서 초점을 맞추고 있는 것은, 기존의 X86 기반에서 MicroC/OS-II Realtime Kernel 이 PXA255 로 아키텍처가 바뀌면서 달라진 것들이다.
수행이 되는 순서에 따라서 하나 하나씩 살펴보도록 하겠다.
부팅 초기화 부분
가장 먼저 수행이 되는 파일로 start_up.S 이 있다.
/* start up code */ .file "rom_reset.s" #include "pxa255.h" #define SDRAM_BASE_ADDRESS 0xa0000000 /* SDRAM Base Address */ #define CFG_MECR_VAL 0x00000000 #define CFG_MCMEM0_VAL 0x00004204 #define CFG_MCMEM1_VAL 0x00000000 #define CFG_MCATT0_VAL 0x00010504 #define CFG_MCATT1_VAL 0x00000000 #define CFG_MCIO0_VAL 0x00008407 #define CFG_MCIO1_VAL 0x00000000 .equ MonStackSz, (0x10000*3) /* Bigger because enet rcv buffer uses stack */ .equ FiqStackSz, 0x10000 .equ IrqStackSz, 0x10000 .equ AbtStackSz, 0x10000 .equ UndStackSz, 0x10000 .equ SysStackSz, 0x10000 /* 스텍 name 선언 */ .global MonStack .global FiqStack .global IrqStack .global AbtStack .global UndStack .global SysStack /* 스텍 할당 */ .comm MonStack, MonStackSz /* for the SVC mode */ .comm FiqStack, FiqStackSz /* for the FIQ mode */ .comm IrqStack, IrqStackSz /* for the IRQ mode */ .comm AbtStack, AbtStackSz /* for the Abort mode */ .comm UndStack, UndStackSz /* for the Undef mode */ .comm SysStack, SysStackSz /* for the System mode */ .global reset .global coldstart .global warmstart .extern SWIHandler .extern IRQHandler .extern FIQHandler .text /* * 0x00000000 번지의 Exception table (Flash Area) */ reset: b coldstart b undefined_instruction b SWIHandler b abort_prefetch b abort_data b not_used b IRQHandler b FIQHandler .align 4 undefined_instruction: b undefined_instruction software_interrupt: b software_interrupt abort_prefetch: b abort_prefetch abort_data: b abort_data not_used: b not_used interrupt_request: ldr pc , =0xa0000004 fast_interrupt_request: ldr pc , =0xa0000008 coldstart: /* * MMU, Icache, Dcache,write buffer 를 disable한다. * ARM CORE의 CPSR를 통해 IRQ,FIRQ를 disable한다. * SVC (supervisory mode)로 동작모드를 설정한다. * reset이 되면 직접 이 위치로 PC가 옮겨진다. * */ ldr r0, =0x2001 /* 모든 coprocessors에 접근을 허용한다 */ mcr p15,0,r0,c15,c1,0 nop nop nop ldr r0, =0x00000078 /* Disable MMU, caches, write buffer */ mcr p15,0,r0,c1,c0,0 nop nop nop ldr r0, =0x00000000 mcr p15,0,r0,c8,c7,0 /* flush TLB's */ mcr p15,0,r0,c7,c7,0 /* flush Caches */ mcr p15,0,r0,c7,c10,4 /* Flush Write Buffer */ nop nop nop mvn r0, #0 /* grant manager access to all domains */ mcr p15,0,r0,c3,c0,0 /* * PXA250 interrupt controller 를 초기화 한다. */ /* Mask off all IRQs and FIQs */ ldr r1, =(INT_BASE | INT_ICMR) ldr r2, =0x0 /* 모든 interrupt를 mask off 시킨다 */ str r2, [r1] /* * PXA250 Clock Register 를 초기화 한다. */ ldr r1, =CLK_BASE /* base of clock registers */ ldr r2, =0x00000241 /* memory clock:100MHz, nomal core clock:200MHz, turbo mode:400MHz */ str r2, [r1, #CLK_CCCR] /* * PXA250 Core Clock를 Turbo Mode로 설정한다. */ ldr r0,=0 mrc p14,0,r0,c6,c0,0 ldr r0,=3 mcr p14,0,r0,c6,c0,0 /* OS Timer를 초기화 한다. */ ldr r1, =TMR_BASE /* reset the OS Timer Count to zero */ mov r2, #0 str r2, [r1, #TMR_OSCR] ldr r4, =0x300 /* really 0x2E1 (0.27uS * 0x2E1 = 198uS) is about 200usec, */ /* so 0x300 should be plenty :Wait OS Timer Stabilize */ 1: ldr r2, [r1, #TMR_OSCR] cmp r4, r2 bgt 1b init_gpio: // FFUART ldr r12, =FFUART_BASE ldr r0, =0x00000000 str r0, [r12, #FFLCR] ldr r0, =0x00000000 str r0, [r12, #FFIER] ldr r0, =0x00000080 str r0, [r12, #FFLCR] ldr r0, =0x00000018 str r0, [r12, #FFDLL] ldr r0, =0x00000000 str r0, [r12, #FFDLH] ldr r0, =0x00000000 str r0, [r12, #FFLCR] ldr r0, =0x00000003 str r0, [r12, #FFLCR] ldr r0, =0x00000001 str r0, [r12, #FFFCR] ldr r0, =0x00000007 str r0, [r12, #FFFCR] ldr r0, =0x00000000 str r0, [r12, #FFIER] ldr r0, =0x00000000 str r0, [r12, #FFMCR] ldr r0, =FFISR_VALUE str r0, [r12, #FFISR] ldr r12, =FFUART_BASE ldr r0, =0x00000040 str r0, [r12, #FFIER] // clear the rx fifo errors ldr r0, =FFFCR_VALUE and r0, r0, #0x00000002 str r0, [r12, #FFFCR] // First set the output values to a safe/disabled state before we change // any GPIO's outputs // start by settings all of them high which is the safest for most signals ldr r12, =GPIO_BASE ldr r0, =0xffffffff str r0, [r12, #GPIO_GPSR0] str r0, [r12, #GPIO_GPSR1] str r0, [r12, #GPIO_GPSR2] // GPCR0 // Now clear any high true outputs that need to start low ldr r0, =(GPIO_7 | GPIO_13 | GPIO_17 | GPIO_27) // USB speed = high // PRST = deasserted // BKL_ON // Passive LCD enable = off str r0, [r12, #GPIO_GPCR0] // Next, set the correct direction for out functions. A one meas output. ldr r0, =(GPIO_3 | GPIO_4 | GPIO_6 | GPIO_7 | GPIO_11 | GPIO_13 | GPIO_15 | GPIO_17 | GPIO_23 | GPIO_24 | GPIO_25 | GPIO_27 | GPIO_30 | GPIO_31) // GPDR0 str r0, [r12, #GPIO_GPDR0] ldr r0, =(GPIO_32 | GPIO_33 | GPIO_39 | GPIO_40 | GPIO_41 | GPIO_43 | GPIO_45 | GPIO_47 | GPIO_48 | GPIO_49 | GPIO_50 | GPIO_51 | GPIO_52 | GPIO_53 | GPIO_54 | GPIO_55 | GPIO_58 | GPIO_59 | GPIO_60 | GPIO_61 | GPIO_62 | GPIO_63) //GPDR1 str r0, [r12, #GPIO_GPDR1] ldr r0, =(GPIO_64 | GPIO_65 | GPIO_66 | GPIO_67 | GPIO_68 | GPIO_69 | GPIO_70 | GPIO_71 | GPIO_72 | GPIO_73 | GPIO_74 | GPIO_75 | GPIO_76 | GPIO_77 | GPIO_78 | GPIO_79 | GPIO_80 | GPIO_81 | GPIO_84) // GPDR2 str r0, [r12, #GPIO_GPDR2] // Finally, set the alternate function registers to the correct state ldr r0, =GPIO_15_AF_CS1; str r0, [r12, #GPIO_GAFR0L] ldr r0, =(GPIO_18_AF_RDY | GPIO_23_AF_SSP_CLK | GPIO_24_AF_SSP_FRM | GPIO_25_AF_SSP_TXD | GPIO_26_AF_SSP_RXD | GPIO_28_AF_AC97_BCLK_IN | GPIO_29_AF_AC97_SDIN0 | GPIO_30_AF_AC97_SDOUT | GPIO_31_AF_AC97_SYNC) str r0, [r12, #GPIO_GAFR0U] ldr r0, =(GPIO_33_AF_CS5 | GPIO_34_AF_FF_RXD | GPIO_35_AF_FF_CTS | GPIO_36_AF_FF_DCD | GPIO_37_AF_FF_DSR | GPIO_38_AF_FF_RI | GPIO_39_AF_FF_TXD | GPIO_40_AF_FF_DTR | GPIO_41_AF_FF_RTS | GPIO_42_AF_BT_RXD | GPIO_43_AF_BT_TXD | GPIO_44_AF_BT_CTS | GPIO_45_AF_BT_RTS | GPIO_46_AF_IR_RXD | GPIO_47_AF_IR_TXD) str r0, [r12, #GPIO_GAFR1L] ldr r0, =(GPIO_48_AF_POE | GPIO_49_AF_PWE | GPIO_50_AF_PIOR | GPIO_51_AF_PIOW | GPIO_52_AF_PCE1 | GPIO_53_AF_PCE2 | GPIO_54_AF_PSKTSEL | GPIO_55_AF_PREG | GPIO_56_AF_PWAIT | GPIO_57_AF_IOIS16 | GPIO_58_AF_LDD0 | GPIO_59_AF_LDD1 | GPIO_60_AF_LDD2 | GPIO_61_AF_LDD3 | GPIO_62_AF_LDD4 | GPIO_63_AF_LDD5) str r0, [r12, #GPIO_GAFR1U] ldr r0, =(GPIO_64_AF_LDD6 | GPIO_65_AF_LDD7 | GPIO_66_AF_LDD8 | GPIO_67_AF_LDD9 | GPIO_68_AF_LDD10 | GPIO_69_AF_LDD11 | GPIO_70_AF_LDD12 | GPIO_71_AF_LDD13 | GPIO_72_AF_LDD14 | GPIO_73_AF_LDD15 | GPIO_74_AF_LCD_FCLK | GPIO_75_AF_LCD_LCLK | GPIO_76_AF_LCD_PCLK | GPIO_77_AF_LCD_BIAS | GPIO_78_AF_CS2 | GPIO_79_AF_CS3) str r0, [r12, #GPIO_GAFR2L] ldr r0, =GPIO_80_AF_CS4 str r0, [r12, #GPIO_GAFR2U] // // turn on the boot led // ldr r0, =0x00000010 // str r0, [r12, #GPSR0] // Clear the peripheral control registers bits ldr r12, =PSSR ldr r0, =(PSSR_RDH | PSSR_PH) str r0, [r12] //////////////////////////////////////////////////////////////////////////////////////////////////// /* * PXA250 Memory Controller를 초기화 한다. */ ldr r1, =MSC_BASE /* base of memory controller */ /* static memory controller를 초기화 한다 */ ldr r2, =0x123412c0 /* CS0 : flash , CS1 : SMSC LAN91C1111 */ str r2, [r1, #MSC_MSC0] ldr r3, [r1, #MSC_MSC0] ldr r2, =0x3ff923e9 /* CS2 : TD242(USB2.0) , CS3 : 확장 보드(fpga board,iom board) */ str r2, [r1, #MSC_MSC1] ldr r3, [r1, #MSC_MSC1] ldr r2, =0x3ff97ff9 /* CS4 : SL811HS(USB1.0) , CS5 : KEY PAD */ str r2, [r1, #MSC_MSC2] ldr r3, [r1, #MSC_MSC2] /* MECR: Memory Expansion Card Register */ ldr r2, =CFG_MECR_VAL str r2, [r1, #MSC_MECR] ldr r2, [r1, #MSC_MECR] /* MCMEM0: Card Interface slot 0 timing */ ldr r2, =CFG_MCMEM0_VAL str r2, [r1, #MSC_MCMEM0] ldr r2, [r1, #MSC_MCMEM0] /* MCMEM1: Card Interface slot 1 timing */ ldr r2, =CFG_MCMEM1_VAL str r2, [r1, #MSC_MCMEM1] ldr r2, [r1, #MSC_MCMEM1] /* MCATT0: Card Interface Attribute Space Timing, slot 0 */ ldr r2, =CFG_MCATT0_VAL str r2, [r1, #MSC_MCATT0] ldr r2, [r1, #MSC_MCATT0] /* MCATT1: Card Interface Attribute Space Timing, slot 1 */ ldr r2, =CFG_MCATT1_VAL str r2, [r1, #MSC_MCATT1] ldr r2, [r1, #MSC_MCATT1] /* MCIO0: Card Interface I/O Space Timing, slot 0 */ ldr r2, =CFG_MCIO0_VAL str r2, [r1, #MSC_MCIO0] ldr r2, [r1, #MSC_MCIO0] /* MCIO1: Card Interface I/O Space Timing, slot 1 */ ldr r2, =CFG_MCIO1_VAL str r2, [r1, #MSC_MCIO1] ldr r2, [r1, #MSC_MCIO1] /* SDRAM Controller를 100MHz 로 초기화 한다 */ ldr r2, =0x03c00fff /* build MDREFR in a specific order */ str r2, [r1, #MSC_MDREFR] ldr r2, =0x03c00018 /* REF Rate = (64MS/8192 Rows) * 100MHz /32 = 24 */ str r2, [r1, #MSC_MDREFR] ldr r2, =0x03c52018 /* Set K0RUN, K1RUN and K2RUN */ str r2, [r1, #MSC_MDREFR] ldr r2, =0x03852018 /* Clear Self Refresh */ str r2, [r1, #MSC_MDREFR] ldr r2, =0x0385b018 /* Set E0PIN and E1PIN */ str r2, [r1, #MSC_MDREFR] ldr r2, =0x0ac80ac8 /* Set CNFG, but don't enable just yet,CL =3,tRP=3clk,tRC=10clk,tRAS=7clk,tRCD=3clk */ str r2, [r1, #MSC_MDCNFG] /* SDRAM Controller를 50MHz 로 초기화 한다 */ /* pause for ~200usec for SDRAM to init */ ldr r1, =TMR_BASE /* reset the OS Timer Count to zero */ mov r2, #0 str r2, [r1, #TMR_OSCR] ldr r4, =0x300 /* really 0x2E1 (0.27uS * 0x2E1 = 198uS) is about 200usec, */ /* so 0x300 should be plenty */ 1: ldr r2, [r1, #TMR_OSCR] cmp r4, r2 bgt 1b /* force 9 cycles to SDRAM : 모든 sdram bank에 CBR(refrash cycle)이 발생한다. */ ldr r2, =SDRAM_BASE_ADDRESS str r2, [r2] str r2, [r2] str r2, [r2] str r2, [r2] str r2, [r2] str r2, [r2] str r2, [r2] str r2, [r2] str r2, [r2] ldr r1, =MSC_BASE /* base of memory controller */ ldr r2, =0x0acb0acb /* now enable SDRAM */ str r2, [r1, #MSC_MDCNFG] /* and do an MRS */ ldr r2, =0x00000000 str r2, [r1, #MSC_MDMRS] /* sdram initialize 완료 */ #if 1 /* * 동작 모드를 SVC 모드로 설정하고 stack pointer * 를 설정한다 */ stack_pointer_set: /* FIQ mode */ mrs r0, cpsr /* move CPSR to r0 */ bic r0, r0, #0x1f /* clear all mode bits */ orr r0, r0, #0xd1 /* set FIQ mode bits */ msr CPSR_c, r0 /* move back to CPSR */ ldr sp, =(FiqStack + FiqStackSz - 4) /* initialize the stack ptr */ /* IRQ mode */ mrs r0, cpsr /* move CPSR to r0 */ bic r0, r0, #0x1f /* clear all mode bits */ orr r0, r0, #0xd2 /* set IRQ mode bits */ msr CPSR_c, r0 /* move back to CPSR */ ldr sp, =(IrqStack + IrqStackSz - 4) /* initialize the stack ptr */ /* Abort mode */ mrs r0, cpsr /* move CPSR to r0 */ bic r0, r0, #0x1f /* clear all mode bits */ orr r0, r0, #0xd7 /* set Abort mode bits */ msr CPSR_c, r0 /* move back to CPSR */ ldr sp, =(AbtStack + AbtStackSz - 4) /* initialize the stack ptr */ /* Undef mode */ mrs r0, cpsr /* move CPSR to r0 */ bic r0, r0, #0x1f /* clear all mode bits */ orr r0, r0, #0xdb /* set Undef mode bits */ msr CPSR_c, r0 /* move back to CPSR */ ldr sp, =(UndStack + UndStackSz - 4) /* initialize the stack ptr */ /* System mode */ mrs r0, cpsr /* move CPSR to r0 */ bic r0, r0, #0x1f /* clear all mode bits */ orr r0, r0, #0xdf /* set System mode bits */ msr CPSR_c, r0 /* move back to CPSR */ ldr sp, =(SysStack + SysStackSz - 4) /* initialize the stack ptr */ /* 'warmstart' will take us back to SVC mode stack for SVC mode will also be setup in warmstart */ #endif .align 4 warmstart: /* Change (back) to SVC mode */ mrs r0, cpsr /* move CPSR to r0 */ bic r0, r0, #0x1f /* clear all mode bits */ orr r0, r0, #0xd3 /* set System mode bits */ msr CPSR_c, r0 /* move back to CPSR */ /* Reset the stack pointer for the SVC mode (our current mode) */ // ldr sp, =(MonStack + MonStackSz - 4) ldr sp, =(0xa4000000 - 4); /* * 이제 C function 인 cstart()로 jump 한다. */ .align 4 relocate: adr r0, reset // relocate the second stage loader add r2, r0, #(1024 * 1024) // blob maximum size is 64kB ldr r1, =0xa0000000 // r0 = source address // r1 = target address // r2 = source end address // copy_loop: ldmia r0!, {r3-r10} stmia r1!, {r3-r10} cmp r0, r2 ble copy_loop jump_to_c: bl C_Entry /* the C code should never return */ b reset .align 4
코드에 추가된 주석을 보면, 이해할 수 있을 것이다. 실행순서는 처음부터 순차적으로 쭈~욱 수행된다.
처음에 coldstart 를 실행하면,
- MMU, Icache, Dcache,write buffer 를 disable
- ARM CORE의 CPSR를 통해 IRQ,FIRQ 를 disable
- Clock 초기화 및 Timer 초기화
- GPIO 초기화 (※ 필수적이지 않음)
- SDRAM 초기화
- 각 모드(mode) 의 stack pointer 설정
- SVC (supervisory mode)로 동작모드를 설정
- 루프를 돌면서, 메모리 상에 복사
- C 언어 레벨인 C_Entry() 호출
위와 같은 순서로 수행된다.
인터럽트 핸들러 부분
다음은 OS 의 핵심적인 부분이라고 할 수 있는 인터럽트 핸들러, 컨텍스트 스위칭 루틴이 어셈블러 레벨로 구현되어 있다.
//주의 : include는 사용할수 없다. //------------------------------------------------------------------- // Interrupt Controller Register ////////// PXA255인 경우 #define ICR_BASE_REGISTER 0x40d00000 ////////// SA1110인 경우 #if 0 // pjk 050502 //ICR_BASE_REGISTER 0x90050000 #define ICIP_OFFSET 0x00000000 #define ICMR_OFFSET 0x00000004 #define ICLR_OFFSET 0x00000008 #define ICFP_OFFSET 0x00000010 #define ICPR_OFFSET 0x00000020 #define ICCR_OFFSET 0x0000000C #else #define ICIP_OFFSET 0x00000000 #define ICMR_OFFSET 0x00000004 #define ICLR_OFFSET 0x00000008 #define ICFP_OFFSET 0x0000000C #define ICPR_OFFSET 0x00000000 #define ICCR_OFFSET 0x00000014 #endif // Timer Register and Period Setting Value ////////// PXA255인 경우 #define OSTIME_BASE_REGISTER 0x40a00000 ////////// SA1110인 경우 //OSTIME_BASE_REGISTER EQU 0x90000000 #define OSMR0_OFFSET 0x00000000 #define OSMR1_OFFSET 0x00000004 #define OSMR2_OFFSET 0x00000008 #define OSMR3_OFFSET 0x0000000C #define OSCR_OFFSET 0x00000010 #define OSSR_OFFSET 0x00000014 #define OWER_OFFSET 0x00000018 #define OIER_OFFSET 0x0000001C #define PERIOD_VALUE_1MS 3686 #define PERIOD_VALUE_10MS 36864 #define PERIOD_VALUE_100MS 368640 #define PERIOD_VALUE_1000MS 3686400 //------------------------------------------------------------------- .text //***************************************************************************** // // The undefined instruction handler. This is called when an instruction // reaches the execute stage of the ARM pipeline, but is not an instruction // which is recognized by the ARM processor. We don't do anything special to // try and recover. // //***************************************************************************** .global UndefHandler .global SWIHandler .global PAbortHandler .global DAbortHandler .global UnusedHandler .global IRQHandler .global FIQHandler UndefHandler: ////////////////////////////////////////////////////////////////////////////////////// //push //pop ////////////////////////////////////////////////////////////////////////////////////////// movs pc, lr //***************************************************************************** // // The software interrupt handler. 0x00 value is uC/OS-II Kernel Interrupt. // //***************************************************************************** SWIHandler: ////////////////////////////////////////////////////////////////////////////////////// //push // stmfd sp!, {r0} // mov r0, #'k' // bl print_byte // ldmfd sp!, {r0} //pop ////////////////////////////////////////////////////////////////////////////////////////// stmfd sp!, {r0,lr} mrs r0, SPSR stmfd sp!, {r0} ldr r0, [lr, #-4] bic r0, r0, #0xff000000 cmp r0, #0x00 bne Return_SWIHandler UCOSII_KERNEL: ////////////////////////////////////////////////////////////////////////////////////// //push // .extern print_byte // stmfd sp!, {r0} // mov r0, #'b' // bl print_byte // ldmfd sp!, {r0} //pop ////////////////////////////////////////////////////////////////////////////////////////// ldmfd sp!, {r0} msr SPSR, r0 ldmfd sp!, {r0,lr} b OSCtxSw Return_SWIHandler: ////////////////////////////////////////////////////////////////////////////////////// //push //pop ////////////////////////////////////////////////////////////////////////////////////////// ldmfd sp!, {r0} msr SPSR, r0 ldmfd sp!, {r0, lr} movs pc, lr //***************************************************************************** // // The instruction pre-fetch abort handler. This is called when an instruction // reaches the execute state of the ARM pipeline, but the pre-fetch of the // instruction failed due to a MMU error. This doesn't need to do a whole lot // unless we are implementing virtual memory. // //***************************************************************************** PAbortHandler: ////////////////////////////////////////////////////////////////////////////////////// //push //pop ////////////////////////////////////////////////////////////////////////////////////////// subs pc, lr, #4 //***************************************************************************** // // The data abort handler. This is called when a load or store instruction is // executed and the memory access failed due to a MMU error. This doesn't need // to do a whole lot unless we are implementing virtual memory. // //***************************************************************************** DAbortHandler: ////////////////////////////////////////////////////////////////////////////////////// //push //pop ////////////////////////////////////////////////////////////////////////////////////////// subs pc, lr, #8 //***************************************************************************** // // The unused vector handler. This is a legacy vector which existed on older // ARM processors but is unused by the ARM7 processor. This vector should // never be called. // //***************************************************************************** UnusedHandler: movs pc, lr //***************************************************************************** // // The IRQ interrupt handler. This is called when the IRQ line going into the // ARM processor goes high, indicating an external device is requesting the // attention of the processor. // //***************************************************************************** IRQHandler: //추가된 부분 시작 mrs r8, SPSR ldr r12,=ICR_BASE_REGISTER ldr r11,[r12, #ICPR_OFFSET] ldr r10, =0x04000000 tst r10, r11 // .extern OSTimer0IRQ bne OSTimer0IRQ msr SPSR, r8 //추가된 부분 끝 subs pc,lr,#4 //***************************************************************************** // // The FIQ interrupt handler. // //***************************************************************************** FIQHandler: mrs r8, SPSR ldr r12,=ICR_BASE_REGISTER ldr r11,[r12, #ICFP_OFFSET] ldr r10, =0x04000000 tst r10, r11 // .extern OSTimer0FIQ bne OSTimer0FIQ //-------- 초가되는 부분 시작 --------------------- stmfd sp!, {r0-r12,lr} //// push //----RTC와 비교 ldr r11,[r12, #ICFP_OFFSET] ldr r10, =0x80000000 //RTC tst r10, r11 // .extern RTC_IRQ // blne RTC_IRQ ldr r12,=0x90040018 ////GEDR : Edge dectect register mov r11, #0x0ff str r11,[r12] ldmfd sp!, {r0-r12,lr} //// pop msr SPSR, r8 subs pc,lr,#4 //-------- 초가되는 부분 끝 --------------------- msr SPSR, r8 subs pc,lr,#4 //**** SWI_Interrupt_OS_Task_Sw **************************************************** // This Function is OS_TASK_SW. It is setting F bit to CPSR. SWI interrupt don't // change F bit. OSTickISR is setting FIQ Interrupt. // .global SWI_Interrupt_OS_Task_Sw SWI_Interrupt_OS_Task_Sw: stmfd sp!, {r0,lr} mrs r0, CPSR // r0 <- CPSR // orr r0, r0, #0x40 // F bit set orr r0, r0, #0x80 // I bit set msr CPSR_c,r0 // Control field of CPSR updata ////////////////////////////////////////////////////////////////////////////////////// //push // stmfd sp!, {r0} // .extern print_byte // mov r0, #'a' // bl print_byte // ldmfd sp!, {r0} //pop ////////////////////////////////////////////////////////////////////////////////////////// swi 0x00 // uC/OS-II call ////////////////////////////////////////////////////////////////////////////////////// //push // stmfd sp!, {r0} // .extern print_byte // mov r0, #'s' // bl print_byte // ldmfd sp!, {r0} //pop ////////////////////////////////////////////////////////////////////////////////////////// ldmfd sp!, {r0,pc} //**** OSTimer0 ************************************************************ // // // .global OSTimer0IRQ OSTimer0IRQ: ldr r12, =OSTIME_BASE_REGISTER //OSTimer Interrupt Source Bit Clear mov r11, #0x01 str r11, [r12, #OSSR_OFFSET] ldr r11, [r12, #OSCR_OFFSET] ldr r10, =PERIOD_VALUE_10MS add r10, r10, r11 str r10, [r12, #OSMR0_OFFSET] stmfd sp!, {r0-r3} mov r2,sp // copy IRQ's sp -> r2 add sp,sp,#16 // recover IRQ's sp sub r3,lr,#4 // copy return address -> r3 mov r1, r8 // copy SPSR -> r1 (SPSR=r8) orr r1, r1, #0x80 // I bit Setting msr SPSR, r1 // update SPSR ldr r0,=OSTickISR_IRQ movs pc,r0 // Mode Change from IRQ mode to SVC mode // .global OSTimer0FIQ OSTimer0FIQ: ldr r12, =OSTIME_BASE_REGISTER //OSTimer Interrupt Source Bit Clear mov r11, #0x01 str r11, [r12, #OSSR_OFFSET] ldr r11, [r12, #OSCR_OFFSET] ldr r10, =PERIOD_VALUE_10MS add r10, r10, r11 str r10, [r12, #OSMR0_OFFSET] stmfd sp!, {r0-r3} mov r2,sp // copy FIQ's sp -> r2 add sp,sp,#16 // recover FIQ's sp sub r3,lr,#4 // copy return address -> r3 mov r1, r8 // copy SPSR -> r1 (SPSR=r8) orr r1, r1, #0x40 // F bit Setting msr SPSR, r1 // update SPSR ldr r0,=OSTickISR movs pc,r0 // Mode Change from FIQ mode to SVC mode //*** OSTickISR **************************************************************** // // The mode of OSTickISR is SVC. This Routine is Critical section of code. // Then, F and I bit of CPSR is set. // .extern OSIntNesting .extern OSTimeTick .extern OSIntExit OSTickISR: stmfd sp!,{r3} // push SVC's pc stmfd sp!,{r4-r12,lr} // push SVC's r14, r12-r4 mov r4,r2 // copy FIQ's sp -> r4 ldmfd r4!,{r0-r3} // pop SVC's r3-r0 stmfd sp!,{r0-r3} // push SVC's r3-r0 mrs r5,CPSR // copy CPSR -> r5 bic r5, r5, #0x40 // F bit clear stmfd sp!,{r5} // push SVC's CPSR ldr r0,=OSIntNesting // Notify uC/OS-II of ISR ldrb r1,[r0] ADD r1,r1,#1 strb r1,[r0] bl OSTimeTick // Process system tick bl OSIntExit // Notify uC/OS-II of end of ISR ldmfd sp!,{r0} msr SPSR,r0 ldmfd sp!,{r0 - r12, lr , pc}^ OSTickISR_IRQ: stmfd sp!,{r3} // push SVC's pc stmfd sp!,{r4-r12,lr} // push SVC's r14, r12-r4 mov r4,r2 // copy IRQ's sp -> r4 ldmfd r4!,{r0-r3} // pop SVC's r3-r0 stmfd sp!,{r0-r3} // push SVC's r3-r0 mrs r5,CPSR // copy CPSR -> r5 bic r5, r5, #0x80 // I bit clear stmfd sp!,{r5} // push SVC's CPSR ldr r0,=OSIntNesting // Notify uC/OS-II of ISR ldrb r1,[r0] ADD r1,r1,#1 strb r1,[r0] bl OSTimeTick // Process system tick bl OSIntExit // Notify uC/OS-II of end of ISR ////////////////////////////////////////////////////////////////////////////////////// //push // stmfd sp!, {r0} // .extern print_byte // mov r0, #'o' // bl print_byte // ldmfd sp!, {r0} //pop ////////////////////////////////////////////////////////////////////////////////////////// ldmfd sp!,{r0} // msr SPSR,r0 msr SPSR,r0 ldmfd sp!,{r0 - r12, lr , pc}^ //**** OS Timer Setting ******************************************************** // // .global OSTimer0_Period_Setting OSTimer0_Period_Setting: stmfd sp!, {r1-r2,lr} ////////////////////////////////////////////////////////////////////////////////////// //push // .extern print_byte // stmfd sp!, {r0} // mov r0, #'z' // bl print_byte // ldmfd sp!, {r0} //pop ////////////////////////////////////////////////////////////////////////////////////////// ldr r2, =OSTIME_BASE_REGISTER mov r1, #0x00 str r1, [r2, #OSCR_OFFSET] ldr r1, =PERIOD_VALUE_10MS str r1, [r2, #OSMR0_OFFSET] mov r1, #0x01 str r1, [r2, #OIER_OFFSET] mov r1, #0x00 str r1, [r2, #OWER_OFFSET] //OSTimer Interrupt Source Bit Clear mov r1, #0x01 str r1, [r2, #OSSR_OFFSET] mov r1, #0x02 str r1, [r2, #OSSR_OFFSET] mov r1, #0x04 str r1, [r2, #OSSR_OFFSET] mov r1, #0x08 str r1, [r2, #OSSR_OFFSET] ldmfd sp!, {r1-r2,pc} //**** OStimer0_Interrupt Setting ******************************************************* // // .global OSTimer0_Interrupt_Setting OSTimer0_Interrupt_Setting: stmfd sp!, {r1-r2, lr} ldr r2, =ICR_BASE_REGISTER ////////////////////////////////////////////////////////////////////////////////////// //push // .extern print_byte // stmfd sp!, {r0} // mov r0, #'y' // bl print_byte // ldmfd sp!, {r0} //pop ////////////////////////////////////////////////////////////////////////////////////////// // mov r1, #0x00 str r1, [r2, #ICCR_OFFSET] //---------- FIQ모드인 경우 // ldr r1, [r2, #ICLR_OFFSET] // //OS Timer Interrupt is set FIQ // orr r1, r1, #0x04000000 // str r1, [r2, #ICLR_OFFSET] //---------- IRQ모드인 경우 ldr r1, [r2, #ICLR_OFFSET] //OS Timer Interrupt is set IRQ bic r1, r1, #0x04000000 str r1, [r2, #ICLR_OFFSET] //OS Timer Interrupt Mask Register Set ldr r1, =0x04000000 str r1, [r2, #ICMR_OFFSET] ldmfd sp!, {r1-r2, pc} //**** Interrupt Mask Service Routine ****************************************** // // .global OSTimer0_Interrupt_Mask_Disable .global OSTimer0_Interrupt_Mask_Enable OSTimer0_Interrupt_Mask_Disable: stmfd sp!, {r0-r2,lr} ldr r2, =ICR_BASE_REGISTER //OS Timer Interrupt Mask Register is Clear ldr r0, =0x04000000 ldr r1, [r2, #ICMR_OFFSET] bic r1, r1, r0 str r1, [r2, #ICMR_OFFSET] ldmfd sp!, {r0-r2,pc} OSTimer0_Interrupt_Mask_Enable: stmfd sp!, {r0-r2,lr} ldr r2, =ICR_BASE_REGISTER //OS Timer Interrupt Mask Register is Set ldr r0, =0x04000000 ldr r1, [r2,#ICMR_OFFSET] orr r1, r1, r0 str r1, [r2,#ICMR_OFFSET] ldmfd sp!, {r0-r2,pc} //***** uC/OS Porting Core Function : OSCtxSw ********************************* // // .extern OSTCBCur .extern OSTaskSwHook .extern OSTCBHighRdy .extern OSPrioCur .extern OSPrioHighRdy .global OSCtxSw OSCtxSw: stmfd sp!,{lr} // push resume address stmfd sp!,{r0 - r12, lr} // push rest context mrs r0,SPSR // bic r0, r0, #0x40 // F bit Clear bic r0, r0, #0x80 // I bit Clear stmfd sp!,{r0} // push CPSR ldr r0,=OSTCBCur // r0 <= &OSTCBCur ldr r0,[r0] // r0 <= OSTCBCur str sp,[r0] // OSTCBCur->OSTCBStkPtr = sp bl OSTaskSwHook // Call user defined task switch hook ldr r0,=OSTCBCur // r0 <= &OSTCBCur ldr r1,=OSTCBHighRdy // r1 <= &OSTCBHighRdy ldr r2,[r1] // r2 <= OSTCBHighRdy str r2,[r0] // OSTCBCur = OSTCBHighRdy ////////////////////////////////////////////////////////////////////////////////////// //push // stmfd sp!, {r0} // .extern print_byte // mov r0, #'c' // bl print_byte // ldmfd sp!, {r0} //pop ////////////////////////////////////////////////////////////////////////////////////////// ldr r0,=OSPrioCur // r0 <= &OSPrioCur ldr r1,=OSPrioHighRdy // r1 <= &OSPrioHighRdy ldrb r3,[r1] // r3 <= OSPrioHighRdy strb r3,[r0] // OSPrioCur = OSPrioHighRdy ldr sp,[r2] // sp <= OSTCBHighRdy->OSTCBStkPtr ldmfd sp!,{r0} // restore SP... msr SPSR,r0 ldmfd sp!,{r0 - r12, lr,pc}^ // Load task's context & SPSR-> CPSR & Run task //**** uC/OS Porting Core Function : OSIntCtxSw ************************************* // // .extern OSTCBCur .extern OSTaskSwHook .extern OSTCBHighRdy .extern OSPrioCur .extern OSPrioHighRdy .global OSIntCtxSw OSIntCtxSw: ADD sp,sp,#4 ldr r0,=OSTCBCur // r0 <= &OSCTBCur ldr r0,[r0] // r0 <= OSCTBCur str sp,[r0] // OSTCBCur->OSTCBStkPtr = sp bl OSTaskSwHook // Call user defined task switch hook ldr r0,=OSTCBCur // r0 <= &OSTCBCur ldr r1,=OSTCBHighRdy // r1 <= &OSTCBHighRdy ldr r2,[r1] // r2 <= OSTCBHighRdy str r2,[r0] // OSTCBCur = OSTCBHighRdy ldr r0,=OSPrioCur // r0 <= &OSPrioCur ldr r1,=OSPrioHighRdy // r1 <= &OSPrioHighRdy ldrb r3,[r1] // r3 <= OSPrioHighRdy strb r3,[r0] // OSPrioCur = OSPrioHighRdy ldr sp,[r2] // sp <= OSTCBHighRdy->OSTCBStkPtr ldmfd sp!,{r0} // restore SP... msr SPSR,r0 ldmfd sp!,{r0 - r12, lr , pc}^ // Load task's context & Run task //**** uC/OS Porting Core Function : OSStartHighRdy ********************************* // // .extern OSTaskSwHook .extern OSRunning .extern OSTCBHighRdy .global OSStartHighRdy OSStartHighRdy: bl OSTaskSwHook // Call user defined task switch hook ldr r0,=OSRunning // Indicate that multitasking has started mov r1,#1 strb r1,[r0] // .extern print_hex // bl print_hex ldr r0,=OSTCBHighRdy // r0 <= &OSTCBHighRdy ldr r0,[r0] // r0 <= OSTCBHighRdy // bl print_hex ldr sp,[r0] // sp <= OSTCBHighRdy->OSTCBStkPtr ldmfd sp!,{r0} // restore SP... msr CPSR,r0 // CPSR <- R0 ldmfd sp!,{r0 - r12, lr , pc} // Load task's context & Run task //****** Interrupt Disable ************************************ // .global GPIO_Interrupt_Disable GPIO_Interrupt_Disable: stmfd sp!, {r1-r2, lr} ////push //-------------초기화 시작------------ ldr r2,=0x90050000 mov r1, #0x0 str r1, [r2, #0x04] //-------------초기화 끝------------ ldmfd sp!, {r1-r2, pc} //****** RTC_Interrupt_Settint ************************************ // .global RTC_Interrupt_Setting RTC_Interrupt_Setting: stmfd sp!, {r1-r2, lr} ////push //-------------초기화 시작------------ ldr r2, =0x90050000 ldr r1, [r2, #0x04] // orr r1, r1, #0x80000000 str r1, [r2, #0x04] // ldr r1, [r2, #0x08] // orr r1, r1, #0x80000000 str r1, [r2, #0x08] // ldr r2, =0x90010000 // RTTR &= 0x0000// // RTTR Register Clock Divider Count = 0 , RTC Clock is 32.768 KHz mov r1, #0x0 str r1, [r2, #0x08] //RTTR, [9001 0008] <- 0 //RTSR |= RTSR_ALE// ldr r1, [r2, #0x10] // orr r1, r1, #0x04 str r1, [r2, #0x10] // //RCNR = 0// mov r1, #0x0 str r1, [r2, #0x04] // //time_value = 32768// //RTAR = time_value// //mov r1, 32768 // 1초 mov r1, r0 // 2초 str r1, [r2, #0x00] // //-------------초기화 끝------------ ldmfd sp!, {r1-r2, pc} /////////////////////////////////////////////// //****** RTC_Interrupt_Disable ************************************ // .global RTC_Interrupt_Disable RTC_Interrupt_Disable: stmfd sp!, {r1-r2, lr} ////push //-------------초기화 시작------------ ldr r2, =0x90010000 //RTSR &= ~RTSR_ALE// ldr r1, [r2, #0x10] // bic r1, r1, #0x04 str r1, [r2, #0x10] // //-------------초기화 끝------------ ldmfd sp!, {r1-r2, pc} .align 4