/*! \brief C part of the SVC exception handler SVC 0 is initializing the OS and starting the scheduler. Each thread stack frame is initialized. \param svc_args Used to extract the SVC number */ void SVC_Handler_C(unsigned int * svc_args) { uint8_t svc_number; svc_number = ((char *) svc_args[6])[-2]; // Memory[(Stacked PC)-2] // marking kernel as busy kernel_busy = 1; switch(svc_number) { //************* SVC( 0 ) OS Start case (0): // OS start // Starting the task scheduler //TWP playing a trick here!? by making curr = next, will make next's stack and current's stack the same stack! // will save (garbage) current register values, and then immediately restore them as next's initial values :-) curr_task = rtr_q_h; // Switch to head ready-to-run task (Current task) // when current task was put in RTRQ its state was set to RUNNING svc_exc_return = HW32_REG(( curr_task->stack_p )); // Return to thread with PSP __set_PSP(( (uint32_t) curr_task->stack_p + 10*4)); // Set PSP to @R0 of task 0 exception stack frame NVIC_SetPriority(PendSV_IRQn, 0xFF); // Set PendSV to lowest possible priority if (SysTick_Config(os_sysTickTicks) != 0) // 1000 Hz SysTick interrupt on 16MHz core clock { stop_cpu2; // Impossible SysTick_Config number of ticks } __set_CONTROL(0x3); // Switch to use Process Stack, unprivileged state __ISB(); // Execute ISB after changing CONTROL (architectural recommendation) break; //************* SVC( 1 ) Thread Yield case (1): // Thread Yield if (curr_task != rtr_q_h) { // Context switching needed ScheduleContextSwitch(); } __ISB(); break; //************* SVC( 2 ) Stack Frame Allocation for First Launch //TWPV6: no longer used! Functionality moved to osThreadCreate ... case left here (for now) case (2): // Stack Allocation __ISB(); break; default: #if ((ENABLE_KERNEL_PRINTF) && (ENABLE_KERNEL_PRINTF == 1)) printf("ERROR: Unknown SVC service number\n\r"); printf("- SVC number 0x%x\n\r", svc_number); #endif stop_cpu2; break; } // end switch // marking kernel as normal kernel_busy = 0; }
/*! \brief Invokes the scheduler Increment systick counter, invoke scheduler and flag any context switching needed for PendSV to take care of. */ void SysTick_Handler(void) // 1KHz { os_KernelEnterCriticalSection(); // Increment systick counter systick_count++; // Run scheduler to determine if a context switch is needed scheduler(); if (curr_task != next_task) { // Context switching needed ScheduleContextSwitch(); } os_KernelExitCriticalSection(); return; }
/*! \brief C part of the SVC exception handler SVC 0 is initializing the OS and starting the scheduler. Each thread stack frame is initialized. \param svc_args Used to extract the SVC number */ void SVC_Handler_C(unsigned int * svc_args) { uint8_t svc_number, i; svc_number = ((char *) svc_args[6])[-2]; // Memory[(Stacked PC)-2] // marking kernel as busy kernel_busy = 1; switch(svc_number) { case (0): // OS start // Starting the task scheduler // Update thread to be run based on priority scheduler(); curr_task = next_task; // Switch to head ready-to-run task (Current task) th_q_h = curr_task; th_q[curr_task]->status = TH_RUNNING; if (PSP_array[curr_task] == NULL) { // Stack not allocated for current task, allocating i = curr_task; th_q[i]->stack_p = (uint32_t) task_stack[i]; PSP_array[i] = ((unsigned int) th_q[i]->stack_p) + (th_q[i]->stack_size) - 18*4; HW32_REG((PSP_array[i] + (16<<2))) = (unsigned long) th_q[i]->start_p; // initial Program Counter HW32_REG((PSP_array[i] + (17<<2))) = 0x01000000; // initial xPSR HW32_REG((PSP_array[i] )) = 0xFFFFFFFDUL; // initial EXC_RETURN HW32_REG((PSP_array[i] + ( 1<<2))) = 0x3;// initial CONTROL : unprivileged, PSP th_q[i]->stack_p = PSP_array[i]; } svc_exc_return = HW32_REG((PSP_array[curr_task])); // Return to thread with PSP __set_PSP((PSP_array[curr_task] + 10*4)); // Set PSP to @R0 of task 0 exception stack frame NVIC_SetPriority(PendSV_IRQn, 0xFF); // Set PendSV to lowest possible priority if (SysTick_Config(os_sysTickTicks) != 0) // 1000 Hz SysTick interrupt on 16MHz core clock { stop_cpu2; // Impossible SysTick_Config number of ticks } __set_CONTROL(0x3); // Switch to use Process Stack, unprivileged state __ISB(); // Execute ISB after changing CONTROL (architectural recommendation) break; case (1): // Thread Yield // Run scheduler to determine if a context switch is needed scheduler(); if (curr_task != next_task) { // Context switching needed ScheduleContextSwitch(); } __ISB(); break; case (2): // Stack Allocation // Create stack frame for thread i = svc_args[0]; th_q[i]->stack_p = (uint32_t) task_stack[i]; PSP_array[i] = ((unsigned int) th_q[i]->stack_p) + (th_q[i]->stack_size) - 18*4; HW32_REG((PSP_array[i] + (16<<2))) = (unsigned long) th_q[i]->start_p; // initial Program Counter HW32_REG((PSP_array[i] + (17<<2))) = 0x01000000; // initial xPSR HW32_REG((PSP_array[i] )) = 0xFFFFFFFDUL; // initial EXC_RETURN HW32_REG((PSP_array[i] + ( 1<<2))) = 0x3;// initial CONTROL : unprivileged, PSP th_q[i]->stack_p = PSP_array[i]; __ISB(); break; default: #if ((ENABLE_KERNEL_PRINTF) && (ENABLE_KERNEL_PRINTF == 1)) printf("ERROR: Unknown SVC service number\n\r"); printf("- SVC number 0x%x\n\r", svc_number); #endif stop_cpu2; break; } // end switch // marking kernel as normal kernel_busy = 0; }