ISIX-RTOS - small operating system for ARM microcontrollers 1.2

port_scheduler.c

Go to the documentation of this file.
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 /*-----------------------------------------------------------------------*/
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines