Wednesday 2 November 2011

TASK SWITCHING IN MSP430

                                                        You might have noticed that while we are working on a computer we will be having many processes running at the same time.Actually we have only one processor, and wonder how is this magic happening ? Actually your operating system is time multiplexing your processor ie, each of the process will be allotted a time slot , after which the scheduler of the operating system will find the task which is to be executed, it will run that process for a time quantum . this process is repeated . Which is called a round robin fashion of scheduling the processes . Let us think of task as a small independent code . what we need to do is to make multiple threads for execution. And each of the thread will be executing a task. The advantage is we can concurrently execute the tasks before making multiple threads we should think
about how to make the time quantum for each task . For that we can take the help from the timer . Timer is an inbuilt peripheral device in almost all Micro controllers . A timer is used to get periodic interrupts as configured by the user. for example if the timer is configured to give interrupt in 1 second after each second our process will be interrupted and we can configure the processor in
such a way that the processor will call a function each time when the interrupt occurs . This type of function is called interrupt service routine. Before we transfer control to a thread we will have to save the current state of the currently running task . How can we do it? The current state of the task is contained in each of the processor registers. So by saving the current register of the processor we can save the current tasks state. next we need to execute the next task, for that we need to fill the registers with the save of the other task. A typical task switcher will be like this
fun isr():
 save_states_of_current_task();
 schedule_next_task();
 restore_states_of_scheduled_task();

Task Switching in MSP430
                                                  I had given an introduction about msp430 in my previous blog. I have implemented a task switching demo code for MSP40 MSP430 is having only a 128 bytes ram so we can only implement task switching up to an extend in this micro controller as we lack memory. For task switching we will keep a global array of which holds the stack pointer of each task . Also we will keep a variable which points to the current tasks index. First thing we need to do is to configure timer. Next we need to divide stack for each stack and initialise their stacks . After the initialisation is done you need to enable interrupts . At this point the timer interrupt will occur after some time. When the timer interrupt occurs, into the timer isr we first push all the registers onto the stack then we increment the task id and jump to the next task .
.include "msp430g2x31.inc"

#define TASK_ID 0x270
#define TASK_ARRAY 0x214

org 0xf800

;;;start routeine.
start:
         mov.w #(WDTPW|WDTHOLD), &WDTCTL    ;disable watchdog timer
         mov.w #0x280, SP                   ;initialise stack pointer
         eint                               ;enable interrupt
         mov r2,r4                          ;copy status register to r4
         dint                               ;disable interrupt
         mov.b #255,&P1DIR                  ;configure all pins of port1 as output
         mov.b #0,&P1OUT                    ;make all the pins off
         mov.b #1,&TASK_ID                  ;initialise current task id as 1
         mov.w #(TASSEL_2|MC_1|ID_3), &TACTL;configure timer control register
         mov.w #(CCIE), &TACCTL0            ;enable capture compate interrupt.
         mov.w #100, &TACCR0                ;set capture compare threshold.

  
;;;initialise the stack of task1
       mov.w #0x258,SP  
       push #task1
       push r4
       push 0
       push 0
       mov.w SP,&TASK_ARRAY

;;;intialise the stack of task2
       mov.w #0x230,SP
       mov.w SP,&(TASK_ARRAY - 0x02)

       eint                           ;enable interrupt.
      jmp task2                       ;jump to task1.
gg:   jmp gg                          ;trap in a while loop.

;;;timer isr
isr:
      push.w r4                       ;push r4 because it was used by other tasks
      push.w r7                       ;push r7 because it was used by other tasks
      mov.b &TASK_ID ,r4              ;copy current task's id to r4
      add r4,r4                       ;r4 <- r4 * 2
      mov.w SP,TASK_ARRAY(r4)         ;update the stack pointer of task array
      add #1,&TASK_ID                 ;add 1 to the current task id
      mov.b &TASK_ID,r4               ;move current task id to r4
      cmp #2,r4                       ;compare the current task id with the maximum tasks
      jne non_zero    
      mov.w #0,&TASK_ID               ;if they are equal then make task_id to zero 
      mov.w #0,r4                     ;r4 to zero
non_zero:
     add r4,r4                        ;multiply r4 by 2
     mov.w TASK_ARRAY(r4),SP         ;load stack pointer with new task's SP 
     mov.w SP,r5                     ;mov sp to r5
     add #8,r5                       ;add sp with 8
     mov.w r5,TASK_ARRAY(r4)         ;save back the top of stack to task_array
 
     pop.w r7                        ;pop to r7 
     pop.w r4                        ;pop to r4
     pop.w r2                        ;pop to r2
     pop.w r0                        ;pop to r0 control gone to next task

;;;task1 to execute.
task1:
    xor.b #1,&P1OUT
    mov #50000,r4
    loop1:
       dec r4
       jnz loop1
    jmp task1
 
;;;task2 to execute.
task2:
    xor.b #(1<<6),&P1OUT
    mov #10000,r4
    loop2:
        dec r4
        jnz loop2
    jmp task2

;;vector table.
org 0xfffe                                      ;reset vector
       dw start
org 0xfff2
       dw isr



No comments:

Post a Comment