ISIX-RTOS - small operating system for ARM microcontrollers 1.2
|
00001 #include <isix/config.h> 00002 #include <isix/printk.h> 00003 #include <isix/types.h> 00004 #include <prv/scheduler.h> 00005 00006 00007 /*-----------------------------------------------------------------------*/ 00008 //Save context 00009 #define cpu_save_context() \ 00010 asm volatile ( \ 00011 "mrs r0, psp\t\n" \ 00012 "stmdb r0!, {r4-r11}\t\n" \ 00013 "ldr r3,0f\t\n" \ 00014 "ldr r2,[r3]\t\n" \ 00015 "str r0, [r2]\t\n" \ 00016 "stmdb sp!, {r3,r14}\t\n" \ 00017 "mov r0,%0\t\n" \ 00018 "msr basepri,r0\t\n" \ 00019 ::"i"(ISIX_MAX_SYSCALL_INTERRUPT_PRIORITY) \ 00020 ) 00021 /*-----------------------------------------------------------------------*/ 00022 //Restore context 00023 #define cpu_restore_context() \ 00024 asm volatile ( \ 00025 "mov r0,#0\t\n" \ 00026 "msr basepri,r0\t\n" \ 00027 "ldmia sp!, {r3,r14}\t\n" \ 00028 "ldr r1,[r3]\t\n" \ 00029 "ldr r0, [r1]\t\n" \ 00030 "ldmia r0!, {r4-r11}\t\n" \ 00031 "msr psp, r0\t\n" \ 00032 "bx r14\r\n" \ 00033 ".align 2 \t\n" \ 00034 "0: .word isix_current_task\t\n" \ 00035 ) 00036 00037 /*-----------------------------------------------------------------------*/ 00038 #define portNVIC_INT_CTRL ( ( volatile unsigned long *) 0xe000ed04 ) 00039 #define portNVIC_PENDSVSET 0x10000000 00040 /*-----------------------------------------------------------------------*/ 00041 00042 //System Mode enable IRQ and FIQ 00043 #define INITIAL_XPSR 0x01000000 00044 00045 #ifndef DEBUG_SCHEDULER 00046 #define DEBUG_SCHEDULER DBG_OFF 00047 #endif 00048 00049 /*-----------------------------------------------------------------------*/ 00050 //Pend SV interrupt (context switch) 00051 void pend_svc_isr_vector(void) __attribute__((__interrupt__,naked)); 00052 00053 void pend_svc_isr_vector(void) 00054 { 00055 cpu_save_context(); 00056 00057 isixp_schedule(); 00058 00059 cpu_restore_context(); 00060 } 00061 00062 /*-----------------------------------------------------------------------*/ 00063 //SVC handler call for start the first task 00064 void svc_isr_vector(void) __attribute__((__interrupt__,naked)); 00065 void svc_isr_vector(void) 00066 { 00067 asm volatile( 00068 "ldr r3, 0f\t\n" /* Restore the context. */ 00069 "ldr r1, [r3]\t\n" /* Use pxCurrentTCBConst to get the pxCurrentTCB address. */ 00070 "ldr r0, [r1]\t\n" /* The first item in pxCurrentTCB is the task top of stack. */ 00071 "ldmia r0!, {r4-r11}\t\n" /* Pop the registers that are not automatically saved on exception entry and the critical nesting count. */ 00072 "msr psp, r0\t\n" /* Restore the task stack pointer. */ 00073 "mov r0, #0\t\n" 00074 "msr basepri, r0\t\n" 00075 "orr r14, #0xd\t\n" 00076 "bx r14\n" 00077 ".align 2 \t\n" 00078 "0: .word isix_current_task\t\n" 00079 ); 00080 } 00081 00082 /*-----------------------------------------------------------------------*/ 00083 //Create of stack context 00084 unsigned long* isixp_task_init_stack(unsigned long *sp, task_func_ptr_t pfun, void *param) 00085 { 00086 *sp-- = INITIAL_XPSR; 00087 *sp-- = (unsigned long)pfun; //PC 00088 *sp-- = 0x14; //LR 00089 *sp-- = 0x12; //R12 00090 *sp-- = 0x3; //R3 00091 *sp-- = 0x2; //R2 00092 *sp-- = 0x1; //R1 00093 *sp-- = (unsigned long)param; //R0 00094 /* 00095 *sp-- = 0x11; //R11 00096 *sp-- = 0x10; //R10 00097 *sp-- = 0x9; //R9 00098 *sp-- = 0x8; //R8 00099 *sp-- = 0x7; //R7 00100 *sp-- = 0x6; //R6 00101 *sp-- = 0x5; //R5 00102 *sp = 0x4; //R4 00103 *sp */ 00104 sp -= 7; 00105 return sp; 00106 } 00107 00108 /*-----------------------------------------------------------------------*/ 00109 static void unused_func(void ) {} 00110 void isix_systime_handler(void) __attribute__ ((weak, alias("unused_func"))); 00111 00112 /*-----------------------------------------------------------------------*/ 00113 //Cyclic schedule time interrupt 00114 void systick_isr_vector(void) __attribute__((__interrupt__)); 00115 00116 void systick_isr_vector(void) 00117 { 00118 //Increment system ticks 00119 isixp_enter_critical(); 00120 00121 //Call isix system time handler if used 00122 isix_systime_handler(); 00123 isixp_schedule_time(); 00124 00125 //Clear interrupt mask 00126 isixp_exit_critical(); 00127 00128 #ifdef ISIX_CONFIG_USE_PREEMPTION 00129 /* Set a PendSV to request a context switch. */ 00130 if(isix_scheduler_running) 00131 { 00132 *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; 00133 } 00134 #endif 00135 } 00136 00137 /*-----------------------------------------------------------------------*/ 00138 //Set interrupt mask 00139 void port_set_interrupt_mask(void) 00140 { 00141 asm volatile( "msr BASEPRI,%0\t\n" 00142 ::"r"(ISIX_MAX_SYSCALL_INTERRUPT_PRIORITY) 00143 ); 00144 } 00145 00146 /*-----------------------------------------------------------------------*/ 00147 //Clear interrupt mask 00148 void port_clear_interrupt_mask(void) 00149 { 00150 asm volatile("msr BASEPRI,%0\t\n"::"r"(0)); 00151 } 00152 00153 /*-----------------------------------------------------------------------*/ 00154 //Yield to another task 00155 void port_yield(void ) 00156 { 00157 /* Set a PendSV to request a context switch. */ 00158 *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; 00159 } 00160 00161 /*-----------------------------------------------------------------------*/ 00162 //Start first task by svc call 00163 void port_start_first_task(void) __attribute__((naked)); 00164 void port_start_first_task( void ) 00165 { 00166 __asm volatile( 00167 " ldr r0, =0xE000ED08 \t\n" /* Use the NVIC offset register to locate the stack. */ 00168 "ldr r0, [r0]\t\n" 00169 "ldr r0, [r0]\t\n" 00170 "msr msp, r0\r\n" /* Set the msp back to the start of the stack. */ 00171 "svc 0\r\n" 00172 ); 00173 } 00174 /*-----------------------------------------------------------------------*/