Amanni
Amanni

Reputation: 1934

Context switching in uC/OS (embedded systems)

I'd like to know if its possible to have an interrupt force the scheduler to switch context to a specific task in RTOS. I'm working with microCOS OS

Here is the task which performs the keyscan and posts the character into a mailbox, I need to add some more features to this code like debounce and auto repeat but I need to sort out a trigger mechanism to get it working properly.

I am not sure how to use polling or interrupts to accomplish this

        static  void  AppTaskKeyscan (void *p_arg)
    {
        CPU_INT08U debouncing = 1;
        CPU_INT16U key;
        key_t button={0,0,0};

        (void)p_arg;

         while (DEF_TRUE) 
         {
            static CPU_INT08U pattern;
            key=P10;

            OSTimeDlyHMSM(0, 0, 0, 50);
            P10=0x0E;
            if ((pattern=P10)==0xee)
                {button.data='1', button.live=1;}       
            else if (pattern==0xde)
                {button.data='4', button.live=1;}
            else if (pattern==0xbe)
                {button.data='7', button.live=1;}
            else if (pattern==0x7e)
                {button.data='*', button.live=1;}
            else
            {
                P10=0x0d;
                if ((pattern=P10)==0xed)
                    {button.data='2', button.live=1;}
                else if (pattern==0xdd)
                    {button.data='5', button.live=1;}
                else if (pattern==0xbd)
                    {button.data='8', button.live=1;}
                else if (pattern==0x7d)
                    {button.data='0', button.live=1;}
                else
                {
                    P10=0x0b;
                    if ((pattern=P10)==0xeb)
                        {button.data='3', button.live=1;}
                    else if (pattern==0xdb)
                        {button.data='6', button.live=1;}
                    else if (pattern==0xbb)
                        {button.data='9', button.live=1;}
                    else if (pattern==0x7b)
                        {button.data='#', button.live=1;}
                    else
                    {
                        P10=0x07;
                        if ((pattern=P10)==0xe7)
                            {button.data='A', button.live=1;}
                        else if (pattern==0xd7)
                            {button.data='B', button.live=1;}
                        else if (pattern==0xb7)
                            {button.data='C', button.live=1;}
                        else if (pattern==0x77)
                            {button.data='D', button.live=1;}
                        else
                            button.live=0;
                    }
                }
            }

            P10=pattern; 

            if (button.live==0)
                OSTimeDlyHMSM(0, 0, 0, 50);
            else
            {
                if (P10==pattern)
                OSTimeDlyHMSM(0, 0, 0, 50);
                else
                button.live=0;
            }

            P10=0x00;              
            if (button.live)        //if button live, set unread flag to 1 and start count down
            {
                button.unread=1;
            }

            if(button.unread&&button.data!='X')
            {
                key=button.data;
                OSMboxPost(KeyMbox, (void *) &key);
                button.live=0;
                button.unread=0;
            }

             OSTimeDlyHMSM(0, 0, 0, 200); 
         } // End of While
    }

Upvotes: 2

Views: 1840

Answers (3)

Clifford
Clifford

Reputation: 93564

You must use an available interrupt compatible (i.e non-blocking) IPC mechanism to signal a task. The simplest method of servicing a keyboard is for the ISR to place the key code in a queue. Any task wanting user input would read from this queue.

Alternatively you could simply have the ISR increment a counting semaphore, and defer keyboard decode to a task, which may then place characters in a queue that may be read by any task reading user input. This may be preferable if the decode is lengthy or variable in execution time.

Specifically in uC/OS-II an ISR that requires the scheduler to run must use the OSIntEnter() and OSIntExit() calls. It is OSIntExit() that causes the scheduler to run when the last nested interrupt completes. Tasks will then be scheduled according to the scheduling policy. It is not possible to circumvent the policy in order to force a specific task to run against the scheduling policy, nor should you want to! If a specific task must run, then make it the highest priority.

Normally the ISR prologue/epilogue functions are only required for ISRs that make OS calls, since one that does not will not cause the scheduler to need to run.

Upvotes: 0

TJD
TJD

Reputation: 11896

The typical way to do this would be to have a keyboard processing task that has a loop where it pends on a semaphore. The keyboard interrupt handler would post the semaphore, which would cause the processing task to become ready and execute.

Upvotes: 2

Adrian
Adrian

Reputation: 5681

The scheduler normally does this. It's its job to know when to do context switch based on priorities of processes/threads (given thread/process aware scheduler)

Edit:

A reason as to why this is not done

Imagine an intruder spawning a low priority task forcing the CPU to context switch (from say higher priority task) to executing some mallicious payload

Upvotes: 0

Related Questions