Saturday, June 29, 2013

Semaphore Vs Mutex: Deletion

① Delete Semaphore or Mutex
 
Similar to creation of mutex, deletion cannot be done from interrupt context. Deletion can be done from task contexts which has some priority value. All the waiting tasks in the queue are just waken up and E_DLT is set as return error code for them. However, deletion of mutex is assumed to be called after unlock of resource.
 
Deletion of semaphore is same as mutex.

② uITRON implementation to delete semaphore

ER del_sem(ID semid)
{
        Check context. If called from ISR,
                return E_CTX;
        Sanity check on arguments
        Enter critical section (Interrupt Disable)
        If (semaphore resource count == 0) { /* some task may be waiting */
                For each task waiting on the semaphore's queue {
                        Set E_DLT at the error code register of task's context
                        If task is waiting for timeout {
                                Delete task from timer queue
                        }
                        Set task's status as Ready
                        If task is not in suspended state {
                                Change the task from semaphore's queue to ready queue
                                If executing task's priority is lower than the waiting,
                                    set to execute scheduler when quitting this function
                        }
                        else {
                                Delete the task from the semaphore queue
                        }
                }
        }
        Release resources allocated when creating semaphore(Release semaphore's queue)
        If scheduler has to be executed {
                Call scheduler
                Return the error code in the context's error code register
        }
        Exit critical section (Interrupt Restore)
        return E_OK;
}

③ uITRON implementation to delete mutex

ER del_mtx(ID mtxid)
{
        Check context. If called from ISR,
                return E_CTX;
        Sanity check on arguments
        Enter critical section (Interrupt Disable)
        For each task waiting on the mutex's queue {
                Set E_DLT at the error code register of task's context
                If task is waiting for timeout {
                        Delete task from timer queue
                }
                Set task's status as Ready
                If task is not in suspended state {
                        Change the task from mutex's queue to ready queue
                        If executing task's priority is lower than the waiting,
                           set to execute scheduler when quitting this function
                }
                else {
                        Delete the task from the mutex queue
                }
        }
        If this mutex has been locked by any task {
                Remove the mutex from the task's mutex list
        }
        Release resources allocated when creating mutex(Release mutex's queue)
        If scheduler has to be executed {
                Call scheduler
                Return the error code in the context's error code register
        }
        Exit critical section (Interrupt Restore)
        return E_OK;
}

For other posts, please look under RTOS label.

Semaphore Vs Mutex: Refer state

① Refer Semaphore and Mutex information

Though it is not very commplex process, just put it for reference.

② uITRON implementation to refer semaphore information

ER ref_mtx(ID mtxid, T_RMTX *pk_rmtx)
{
        Sanity check on arguments
        Enter critical section (Interrupt Disable)
        Store ID number of task locking the mutex
        Store ID number of task which is at the head of mutex's wait queue
        Exit critical section (Interrupt Restore)
        return E_OK;
}

③ uITRON implementation to refer mutex information

ER ref_sem(ID semid, T_RSEM *pk_rsem)
{
        Sanity check on arguments
        Enter critical section (Interrupt Disable)
        Store ID number of task which is at the head of semaphore's wait queue
        Store the semaphore resource count (remaining number of resources)
        Exit critical section (Interrupt Restore)
        return E_OK;
}

For other posts, please under RTOS label.

Tuesday, June 25, 2013

Semaphore Vs Mutex: Signal Semaphore/Unlock Mutex

① Releasing lock or signalling semaphore
The Mutex can be unlocked only by the task which locked it. Unlocking the mutex involves the following two things:
1) bringing the task which is locking, back to the state before locking the mutex. The task is returned to its base priority or if the task is locking other mutexes, highest ceiling priority or highest priority of tasks waiting for such mutexes will be assigned. If the task's priority is lowered down, then the task will call scheduler. Otherwise, it will continue holding the CPU.
2) One of the waiting tasks is granted the lock. The task waiting on the highest priority level of the queue of the mutex is checked as if it called loc_mtx(). If eligible, it is removed from wait queue and lock is granted. If not eligible, error code is posted to that task and next waiting task is considered. If the mutex is with CEILING attribute and the ceiling priority is higher than the task priority, the task priority is raised. Otherwise, the task's priority is set as current highest priority locking the mutex. If the new locking task's priority is higher than the current task's priority, then the scheduler will be called.

But, Semaphore can be signaled from any context. (This may cause accidential release.) And, it just increments the semaphore resource count, if no task is waiting for it. But, if the semaphore is signaled when resource count is at its maximum limit, E_QOVR error is returned and its resource count is set at its maximum value.



② iTRON implementation to signal semaphore

ER sig_sem(ID semid)
{
        Sanity check on arguments
        Enter critical section (Interrupt Disable)
        If (Semaphore resource count == 0){
                /* then some tasks should be waiting */
                Check semaphore queue till queue tail is reached
                If there is valid task id {
                        if task is waiting in Timeout
                                remove from timer queue
                        Set task status ad Ready
                        if the task is NOT suspended {
                                Change the task to the Ready Queue of priority
                                If (the task priority is higher than the current){
                                        call scheduler
                                        return error code from scheduler
                                } else {
                                        Exit critical section and return error code from it (E_OK)
                                        (return E_OK)
                                }
                        } else {
                                Just delete the task from the Semaphore queue
                                Exit critical section and return the error code from it (E_OK)
                                (return E_OK)
                        }
                }
        }
        If (Semaphore resource count reached maximum) {
                Exit critical section
                return E_QOVR;
        } else {
                Increment semaphore resource count
                Exit critical section and return the error code from it (E_OK)
                return E_OK;
        }
}

③ iTRON implementation to unlock mutex

ER unl_mtx(ID mtxid)
{
        Sanity check on arguments
        If (this function is called from interrupt context) or
        If (called from task independent state ex: timer handlers) or
        If (called from dispatch disabled state)
                Return E_CTX;
        Enter critical section (Interrupt Disable)
        If (this task has NOT locked this mutex)
                Return E_ILUSE;
        Take the tasks's base priority
        For all mutexes locked by this task {
                If (mutex ID is same as this mutex) {
                        Release it from queue by assigning the next mutex ID in
                            place of this mutex
                        If this is not FIFO based, continue checking to get back the original priority
                        Otherwise, break the loop
                }
                Does any mutex have higher priority than the base priority?
                Keep it as new priority
        }
        If (new priority is not equal to the current running priority){
                Assign the new priority to the tcb
                Change the tcb to Ready queue with new priority level
                If (new priority is lower than the current running priority)
                        Set to call scheduler when quitting this function
        } else {
                No need to call scheduler
        }
        /* Grant lock to one waiting task and wake it up */
        For all tasks waiting in this mutex's queue (from head having highest priority tasks) {
                Take a task.
                If it is waiting as Timeout, remove it from timer queue
                Remove the task from the mutex's queue
                Set tcb status as Ready
                /* Sanity check and lock assignment as if it called loc_mtx */
                If the mutex attribute is Ceiling and the task has higher base priority {
                /* When ths task is waiting, base priority is changed by chg_pri() */
                        Error code parameter of tcb = E_ILUSE
                        Add the task to the Ready queue
                        If the task's priority is higher than the current task's priority
                                Set to call scheduler when quitting this function
                        Take next task and continue checking from first
                } else {
                        If the mutex has CEILING attribute and
                         the ceiling priority is higher than the task priority{
                                the task (tcb) priority is set to the ceiling priority
                        } else {
                                the task's priority is set as current highest
                                    priority locking the mutex
                        }
                        Set the task as locking task
                        Add the mutex in the task's queue of mutexes
                        If the task's priority is higher than the current task's priority
                                Set to call scheduler when quitting this function
                }
        }
        If to call scheduler {
                Call scheduler
                return error code that is set in scheduler
        }
        Otherwise, exit critical section and return error code from it (E_OK)
}


Please have a look at other posts under RTOS label.

Tuesday, June 18, 2013

Renesas USB Function Driver Analysis


Sunday, June 16, 2013

Renesas USB Function driver does not return from RecvWait()

Problem:

Renesas USB Function driver does not return from USBRecvWait(), even though the USB host keeps sending the data. It seems that BRDYSTS status register is not set and corresponding BRDYSTS interrupt does not occur, even though the data is received on the pipe and CBST bit is set on the PIPECTR register.

This occurs only when the data is transmitted and received simultaneously.
Solution:

Please check the udc_bulk_in0() function. If the BRDYSTS register is cleared using the following function, it will not only clear the intended bit. But, it will clear other status bits too. For example, it will clear the BRDY status of data which is received at the instant between the reading of BRDYSTS register and writing back the logical AND result.

    PRU_REG_CLR_BIT( PUO_HWF_REG_BRDYSTS, PUO_HWF_BRDYSTS_BRDY(pipeno) );

The solution is, it needs to be replaced as follows. Write the logical negation of the bit that has to be cleared.

    PRU_REG_WRITE16( PUO_HWF_REG_BRDYSTS, ~PUO_HWF_BRDYSTS_BRDY(pipeno) );

As mentioned above, the clear of BEMPSTS and INTSTS0 register also has to be replaced as follows:

    PRU_REG_CLR_BIT( PUO_HWF_REG_BEMPSTS, PUO_HWF_BEMPSTS_BEMP(pipeno) );
                             ↓
    PRU_REG_WRITE16( PUO_HWF_REG_BEMPSTS, ~PUO_HWF_BEMPSTS_BEMP(pipeno) );



    PRU_REG_CLR_BIT( PUO_HWF_REG_INTSTS0, xxxxxx );
                             ↓
    PRU_REG_WRITE16( PUO_HWF_REG_INTSTS0, ~xxxxxx );



Step towards a non buggy world!

Renesas OpenVG sample program does not come out of while loop

Problem:

Renesas provided sample program for its built-in OpenVG controller does not come out of while loop in status checking of wait_state() function, when calling OpenVG_init() function.

Solution:

Please check the following conditions:

① Framebuffer is located in Cache-inhibited memory region
② Clock supply to the OpenVG controller is enabled. (Exception also occurs, if the clock supply is not enabled) Please check the setting in Power Save Unit Registers.
③ Correct clock supply is supplied to the Graphics controller. The Clock setting in Clock Controller Unit has to be set correctly to supply 200 MHz to the Image processing unit.
 

Saturday, June 15, 2013

Semaphore Vs Mutex: Lock/Acquire Resources

① Acquiring lock or resource
------------------------------------
Mutex needs to be associated with Task. So, it cannot be locked from task independent contexts such as ISR, timer Handler, cyclic handler, alarm handler. Also, it cannot be locked from dispatch disabled or CPU locked state. Mutex can avoid priority inversion since it implements Priority Inheritence or Priority Ceiling protocols.
 
Semaphore is not like that. Semaphore resources can be acquired or released from even task independent contexts. But, in case of waiting for semaphore resource,it will return E_CTX in task independent contexts. Semaphores are vulnerable to priority inversion scenarios. So, when replacing mutex with binary semaphore, please be aware of this.
 
Mutex checks for nested call. But, semaphore does not. For example, in the folloing case, in case of binary semaphore, deadlock occurs. But, Mutex returns E_ILUSE;

ID SemID;    /* Binary Semaphore ID */

void FunctionA()
{
        wai_sem(SemID);
        FunctionSub();
        sig_sem(SemID);
}

void FunctionSub()
{
        wai_sem(SemID);
                :
        sig_sem(SemID);
}

So, Mutex can avoid priority inversion and recursive locks!

Note that when the task is locking the mutex, the mutex ID is recorded in TCB (Task Control Block) structure. That means, the locked mutex is associated with the locking task and considered as a resource currently occupied by the specific task. So, the task is liable to release the mutex at one point. Other tasks cannot do anything till the locking task releases the mutex. It is like occupying a room locking inside. If any other person trying to occupy the room kept waiting at the entrance till the person inside comes out by unlocking the room.
 
But, semaphore is NOT considered as resource but just a counter which can be incremented and decremented atomically by any anonymous task. Neither the semaphore nor the task does not remember which particular task increment or decrement which semaphore. But, (unluckily) some programmers associate the semaphore with some resources to manage the access of the resources. For example, number of balls in a basket are maintained using two buttons one is read and other is blue. Whenever you take a ball, you should press red button. When you return the ball, you should press the blue button. There are chances of confusion here when somebody forget to press the red button when taking the ball or when somebody just pressed the blue button without actually returning the ball. In this scenario, ball is considered as actual resource maintained by a semaphore. Pressing the red button is similar to incrementing the count. Pressing the blue button is similar to decrementing the count.

② ITRON implementation to acquire semaphore
-----------------------------------------------------------
ER wai_sem(ID semid)
{
        Sanity check on arguments
        If (remaining number of semaphore resrouces is zero) {
                If (this function is called from interrupt context) or
                If (called from task independent state ex: timer handlers) or
                If (called from dispatch disabled state)
                        Return E_CTX;
                If (polling mode)
                        Exit critical section and return E_TMOUT;
                If (Timeout value is specified) {
                        Add task into timer queue;
                        Set TCB flags that 'Waiting for Semaphore, Check for Timeout'
                } else (Wait forever) {
                        Set TCB flags that 'Waiting forever for Semaphore'
                }
                Set Semaphore ID in TCB
                Select Queue according to queueing order
                If (Tasks should be granted in FIFO order)
                        Select Semaphore->Queue[0] as Queue
                Else (Should be granted in Priority order)
                        Select Semaphore->Queue[Current Tasks Priority]
                Change the task from ReadyQueue to the Semaphore Queue
                Schedule the tasks, since this task is going to sleep
                (Once the task is released, execution will return here)
                Return the value set by scheduler(Scheduler directly set return value before return here)
        }
        Reduce Semaphore resource count by one
        Exit critical secion
        Return E_OK;
}

③ ITRON implementation to lock mutex
--------------------------------------------------
ER loc_mtx(ID mtxid)
{
        Sanity check on arguments
        If (this function is called from interrupt context) or
        If (called from task independent state ex: timer handlers) or
        If (called from dispatch disabled state)
                Return E_CTX;
        Enter critical section (Interrupt Disable)
        If (same task has locked this mutex already)
                Return E_ILUSE;
        If (Ceiling protocol has been selected) and
            (this task has high base priority than the ceiling priority)
                Return E_ILUSE;
        If (this mutext has NOT been locked already (by any other task)) {
                Record this task ID as locking task in mutex structure
                (Refer from TCB & Record the previous mutex ID locked by the same task)
                (Update this mutex ID as previous mutex ID in TCB structure)
                If (Ceiling protocol) and
                    (this tasks's (running) priority* is less than ceiling priority) {
                        Change the task's priority to ceiling priority
                        Schedule the tasks, since the priority has been changed
                        (If any higher priority task exists, that will be executed and control returns here later)
                        Return value from scheduler(Scheduler directly set return value before return here)
                }
        } else { /* Has been locked. If not polling mode, process queuing */
                If (polling mode)
                        Exit critical section and return E_TMOUT;
                If (Timeout value is specified) {
                        Add task into timer queue;
                        Set TCB flags that 'Waiting for Mutex, Check for Timeout'
                } else (Wait forever) {
                        Set TCB flags that 'Waiting forever for Mutex'
                }
                Set MutexID in TCB
                Select Queue according to queueing order
                If (Tasks should be granted in FIFO order)
                        Select mutex->Queue[0] as Queue
                Else (Should be granted in Priority order)
                        Select mutex->Queue[Current Tasks Priority]
                Change the task from ReadyQueue to the Mutex Queue
                If (Priority Inheritence protocol selected) and
                    (this task has high priority than locked task)
                        Raise the priority of the locked task
                Schedule the tasks, since this task is going to sleep
                (Once the task is released, execution will return here)
                Return the value set by scheduler(Scheduler directly set return value before return here)
        }
        Exit critical section and return E_OK;
}

* running priority - Specifies the priority changed inside the kernel. For example, priority raised through priority inheritence or priority ceiiling protocol.
Base priority is the one set by user program. For example, the priority set during creation or chg_pri() system call.

The Queue is maitained as follows. When chaning a queue, entry is deleted from existing queue (Ready Queue) and added to the new Queue.

Raise_priority()
{
        Take the task (say A) currently locking the mutex
        Take the base priority of the task A
        Parse through all the mutex locked by A {
            Fix the maximum (say P) between
            the maximum priority of all waiting tasks over mutex of INHERIT and
            the maximum of celing priority of mutex with CEILING
            And, for all the INHERIT mutexes, the priority of locking task has
            to be reset with the maximum priority of all waiting tasks. If no
            waitint task, then the priority is reset with minimum system priority.
        }
        If the priority P is not equal to the running priority of locking task{
                Assign the P as running priority of locking task
        }
}

Thursday, June 13, 2013

Semaphore Vs Mutex: Creation

See some implementation differences between semaphore annd mutex:

① Arguments to create a semaphore and mutex:
----------------------------------------------------------
Semaphore needs a) count = Total number of resoures to be maintained by this semaphore. For binary semaphore, this will be one. b) initial count = Number of resources acquired at initialization c) Order = Order in which the tasks should be granted with resources. FIFO or Priority Based
 
Mutex needs a) protocol = Protocol to be used to avoid priority inversion. It can be "Priority inheritence" or "Priority Ceiling". b) ceiling priority = Value of ceiling priority. It is used only when using Priority Ceiling protocol. c) Order = Order in which the tasks should be granted with resources. FIFO or Priority Based

② ITRON implementation to create semaphore
-------------------------------------------
ER cre_sem(ID semid, T_CSEM *pk_csem)
{
        Check context. If called from ISR,
                return E_CTX;
        Sanity check on arguments
        Enter critical section (Interrupt Disable)
        Initialize internal structure with the arguments.
        Internal structure has one queue to order waiting tasks
        If (tasks are queued in FIFO order)
                Initialize queue as follows:
                ┏━━━━━┯━━━━━━┓
                ┃Queue   │Queue     ┃
                ┃[0]     │Tail       ┃
                ┗━━━━━┷━━━━━━┛
        else (tasks are queued as priority based)
                Initialize as follows:
                ┏━━━━━━━━┯━━┯━━━━┯━━━━━━┓
                ┃Priority0      │1   │Max   │Queue    ┃
                ┃            │    │Pri    │Tail       ┃
                ┗━━━━━━━━┷━━┷━━━━┷━━━━━━┛
        Exit critical section (Interrupt Restore)
        return E_OK;
}

③ ITRON implementation to create mutex
---------------------------------------
ER cre_mtx(ID mtxid, T_CMTX *pk_cmtx)
{
        Check context. If called from ISR,
                return E_CTX;
        Sanity check on arguments
        Enter critical section (Interrupt Disable)
        Initialize internal structure with the arguments.
        Decide on priority of tasks that lock the mutex
        If (Ceiling) {
                the priority will be the one specified in argument
        } else if (Priority inheritence) {
                temporarily keep 0.
                Later it will be changed to the highest priority of waiting tasks.
        } else (nothing is specified) {
                It will be Highest priority that can be assigned in the system
        }
        Internal structure has one queue to order waiting tasks
        If (tasks are queued in FIFO order)
                Initialize queue as follows:
                ┏━━━━━┯━━━━━━┓
                ┃Queue   │Queue    ┃
                ┃[0]     │Tail       ┃
                ┗━━━━━┷━━━━━━┛
        else (tasks are queued as priority based)
                Initialize as follows:
                ┏━━━━━━━━┯━━┯━━━━┯━━━━━━┓
                ┃Priority0      │1   │Max   │Queue    ┃
                ┃            │    │Pri    │Tail       ┃
                ┗━━━━━━━━┷━━┷━━━━┷━━━━━━┛
        Exit critical section (Interrupt Restore)
        return E_OK;
}
■ For more details on uITRON APIs and structures
--------------------------------------------------------------
Please refer http://www.ertl.jp/ITRON/SPEC/FILE/mitron-400e.pdf

Check Other posts under RTOS label.