Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- primitive multitasking example for NXP's LPC1788 using IAR IDE
- it contains only two tasks.
- Both tasks are only simple LED flashes in infinite loops.
- tasks are preemted always from one to the other
- it is done by SysTick interrupt handler which switches the context
- 1/ interrupt is set up
- 2/ stack for task 2 created
- 3/ main enters task 1 so task 1 uses stack originally used by main program
- 4/the tasks are regulary interupted and switched to the other one
- */
- #include <nxp/iolpc1788.h>
- #define LED1 (1<<13)
- #define LED2 (1<<18)
- #define STACK_SIZE 50
- unsigned int *task1SP;
- unsigned int *task2SP;
- unsigned int current_task;
- //stack for task 2
- unsigned int stack2 [STACK_SIZE];
- /*change LED state at given IO pin*/
- void flash_LED(unsigned int led){
- //check pin state and change it
- if(FIO1PIN & led){
- FIO1CLR = led;
- }
- else{
- FIO1SET = led;
- }
- }
- /*demo task 1 flash LED1 */
- void task1(){
- while(1){
- //wait
- for(int i=0;i<1000000;i++){
- }
- flash_LED(LED1);
- }
- }
- /*demo task 2 flash LED2 */
- void task2(){
- while(1){
- //wait
- for(int i=0;i<1000000;i++){
- }
- flash_LED(LED2);
- }
- }
- /*basic hw setup */
- void hw_init(){
- // diodes at P1.13 a 15 as output
- FIO1DIR = (1<<13|1<<18);
- //SYSTICK set up
- //enable + interupt + cpu freq
- STCTRL = (0x7);
- // value to count-down for systick reloadREG = (fcpu * T) - 1
- STRELOAD = 0x1D31D;//0xFFFFFE 0xB67753 0x123F22 0x1D31D //max 1s 100ms 10ms
- }
- /*this function sets up a stack for task2. This is the most difficult part.
- contents of the stack from the top adress
- PSR - manual copy from stack of task 1 ;) (Program Status Register)
- PC - adress of task2 (Program Counter)
- LR - to be poped into LR (Link Register)
- R12 - to be poped into
- (R3 to R0) - to be poped into
- EXC_RETURN value - so processor knows that it returns from an interrupt
- 0x0 - from top to this point values are pushed autmatically when entering an
- interrupt and poped back when leaving interrupt
- (R4 to R11) - values to be pushed after context switch
- */
- void create_task2(){
- //init whole array to zeros
- for(int i=0;i<STACK_SIZE;i++){
- stack2[i]=0;
- }
- //target task2SP to end of array stack2
- //so it can grow downwards
- task2SP = &stack2[STACK_SIZE-1];
- //set the stack formation all registers with correct values of PC LR etc
- //comment out =0 (already set)
- *task2SP = 0x81000000; //PSR ?
- task2SP--;
- *task2SP = (unsigned int) ((void *) task2); //PC task2()
- task2SP = task2SP-7;
- *task2SP = 0xFFFFFFF9; //EXC_RETURN
- task2SP = task2SP-9;
- //now task2SP targets to end of stack of task 2
- //ready to be switched into
- }
- void main(){
- //create stack formation for task 2
- create_task2();
- //start with task 1
- current_task = 1;
- //set up systick and other hw
- hw_init();
- //and go into the first task
- task1();
- }
- /* set Stack Pointer */
- void set_sp(void *x){
- asm("MOV SP, R0");
- }
- /* get Stack Pointer */
- void* get_sp(){
- asm("MOV R0, SP");
- //return value is in R0
- }
- //SysTick_Handler function run by the interrupt
- //my simple scheduler
- //switch between task 1 and 2
- void SysTick_Handler(){
- //1 stack what is not automatically stacked
- asm("PUSH {R4-R11}");
- switch (current_task){
- case 1:
- //2 save current stack pointer
- task1SP = get_sp();
- //3 get SP of another task
- set_sp(task2SP);
- current_task=2;
- break;
- case 2:
- //2 save current stack pointer
- task2SP = get_sp();
- //3 get SP of another task
- set_sp(task1SP);
- current_task=1;
- break;
- }
- //4 restore the stack
- asm("POP {R4-R11}");
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement