2

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
    }
Clifford
  • 88,407
  • 13
  • 85
  • 165
Amanni
  • 1,924
  • 6
  • 31
  • 51
  • Why are you using the comma operator in the lines of the form `{button.data='A', button.live=1;}`? – Dan Jan 06 '12 at 05:47

3 Answers3

2

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.

TJD
  • 11,800
  • 1
  • 26
  • 34
0

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

Adrian
  • 5,603
  • 8
  • 53
  • 85
  • when I'm writing a keyscan task and I want to have an interrupt when any key is pressed so how do I get the scheduler to recognize this? – Amanni Jan 05 '12 at 17:02
  • @Amanni normally you have a keyboard interrupt, then you send a message with the key pressed to the keyboard process. The scheduler will know when to run the keyboard process which will pick up the message you send with the pressed key and it will display it or whatever you want to do with it. – Adrian Jan 05 '12 at 17:05
  • Sorry for being a pain but what do you mean keyboard process? – Amanni Jan 05 '12 at 17:10
  • @Amanni it's alright; I'm assuming that you're making the OS. An OS has many processes; you may add as many as you need but some necessary ones are: null process, keyboard, screen, timer. See this post I wrote: http://stackoverflow.com/a/8458921/1007845. Might find this link useful: http://en.wikipedia.org/wiki/Process_%28computing%29 – Adrian Jan 05 '12 at 17:24
  • Thanks alot, I'm not writing the OS, I'm just looking for a trigger for my keyscan and I can decide between using an interrupt or polling or to be specific I can't get either to work. I will edit the question so I can add my code – Amanni Jan 05 '12 at 17:50
0

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.

Clifford
  • 88,407
  • 13
  • 85
  • 165