Actions

EmSys

Embedded Systems Design II Atomthreads rtos

From EdWiki

Atomthreads

atomthread template Project

Install Code Composer Studio
Install TivaWare for C Series
► Launch Code Composer Studio with new workspce.
► Instead of creating a new project, we will Import a pre-configured project from the file system.
► Download atomthreads Template Project.
► To import an existing project into the CCS IDE workspace, select File > Import from the CCS main menu.
► In the Next screen, Select Code Composer Studio > CCS Projects

Ccs import archive project.png

► Click on the Next button.
► In the Import CCS Projects Dialog window, choose Select archive file:, and Browse to atomthreads_on_tivac_template.zip file.
► Make sure Copy projects into workspace button is checked!

Ccs import atomthread project from archive.png

► Click on the Finish button.

Atomthreads on tivac blinky folder.png

► Rename the Project as atomthreads_on_tivac_blinky
► Create CCS Build Variable called TIVAWARE_LOC which should link to the Tivaware folder
Build Project
►Launch Serial terminal emulator (minicom, gtkterm,etc) and configure for 115200,8,1,N
Configure for Debug
Load/Debug/Run the Program

In the Serial terminal window, you should see "Hello, Atomthreads OS" string is displayed. RED Led should be blinking on the Tiva Board.

If you have reached this far, Congratulations!!

References

  1. Introduction to atomthreads
  2. atomthreads kernel Reference
  3. atomthreads Documentation

External Links

  1. atomthreads on github
  2. atomthreads website

Threads Assignment 1

► Launch Code Composer Studio
► Import atomthreads Template Project into the current workspace
►Rename the Project as atomthreads_threads_assignment_one
►Launch Serial terminal emulator (minicom, gtkterm,etc) and configure for 115200,8,1,N
►Create two threads (Task1 and Task2) with equal priorities. Task1 should display the string "Task 1 is Running ..." and Task2 should display the string "Task 2 is Running ...".
►After Displaying the string, introduce a small (software) Delay;

void Taskn(uint32_t entry_param)
{
    while(1) { 
        printf("%s", "Task n is Running ..."); 
        for( auto int32_t ul = 0; ul < 3180; ul++ ) { ; }
    }
}
  • Observe which Tasks strings Displayed and Why?
  • Change Tasks priorities and Observe
  • Delay generated using a null loop
    the task effectively polled an incrementing loop counter until it reached a fixed value.
  • Disadvantages to any form of polling
    While executing the null loop, the task remains in the Ready state, ‘starving’ the other task of any processing time.
    During polling, the task does not really have any work to do, but it still uses maximum processing time and so wastes processor cycles.
  • Replace the polling null loop with a call to atomTimerDelay(); API function corrects this behavior.

References

  1. Introduction to atomthreads
  2. atomthreads kernel Reference
  3. atomthreads Documentation

Threads Assignment 2

The two tasks created in the previous example are almost identical, the only difference between them being the text string they print out. This duplication can be removed by, instead, creating two instances of a single task implementation. The task parameter should be used to pass into each task the string that it should print out.

► Launch Code Composer Studio
► Import atomthreads Template Project into the current workspace
►Rename the Project as atomthreads_threads_assignment_two
►Launch Serial terminal emulator (minicom, gtkterm,etc) and configure for 115200,8,1,N
►Write a single thread function (Thread_Function). The thread parameter should be used to obtain the string the task should print out.

The entry_param parameter of the atomThreadCreate() function is used to pass parameter into the task

  • Even though there is now only one task implementation (Thread_Function), more than one instance of the defined task can be created.
  • Each created instance will execute independently under the control of the atomthreads scheduler.

References

  1. Introduction to atomthreads
  2. atomthreads kernel Reference
  3. atomthreads Documentation

Threads Assignment 3

  • The tasks created in the previous examples spend most of their time in the Blocked state. While in this state, they are not able to run, so cannot be selected by the scheduler.
  • There must always be at least one task that can enter the Running state. To ensure this is the case, an Idle task is automatically created by the scheduler when atomSched() is called. The idle task does very little more than sit in a loop—so, it is always able to run.
  • The idle task has the lowest possible priority (priority 255), to ensure it never prevents a higher priority application task from entering the Running state.
  • It is possible to add application specific functionality directly into the idle task function.


HowTo:

  1. Create two Tasks as in the Atomthreads Threads Assignment One
  2. Modify atomIdleThread() function in the atomkernel.c file which should print the number of idle counts.


Note: An Idle task function must never attempt to block or suspend.

References

  1. Introduction to atomthreads
  2. atomthreads kernel Reference
  3. atomthreads Documentation

Threads Assignment 4

Write an atomTimerDelayUntil() API function

  • atomTimerDelay() function results in the calling task entering into the Blocked state, and then remaining in the Blocked state, for the specified number of ticks from the time atomTimerDelay() was called. The time at which the task that called atomTimerDelay() exits the Blocked state is relative to when atomTimerDelay() was called.
  • Write an API function called atomTimerDelayUntil() which should result in the calling task entering into the Blocked state, and then remaining in the Blocked state, until an absolute time has been reached.
  • The task that calls atomTimerDelayUntil() exits the Blocked state exactly at the specified time, not at a time that is relative to when atomTimerDelayUntil() was called.


atomTimerDelayUntil() function prtotype:

void atomTimerDelayUntil(TickType_t * previousWakeTime,  TickType_t timeIncrement);


previousWakeTime: This parameter should be used on the assumption that atomTimerDelayUntil() is being used to implement a task that executes periodically and with a fixed frequency. In this case previousWakeTime holds the time at which the task last left the Blocked state (was ‘woken’ up). This time is used as a reference point to calculate the time at which the task should next leave the Blocked state. The variable pointed to by previousWakeTime should be updated automatically within the atomTimerDelayUntil() function; it would not normally be modified by the application code, other than when the variable is first initialized.

timeIncrement: This parameter is also named on the assumption that atomTimerDelayUntil() is being used to implement a task that executes periodically and with a fixed frequency – the frequency being set by the timeIncrement value. timeIncrement is specified in ‘ticks’. The MS_TO_TICKS() macro can be used to convert milliseconds to ticks.

How to Use:

/* Define a task that performs an action every 50 milliseconds. */
void periodic_thread(uint32_t entry_param)
{
    TickType_t lastWakeTime;
    const TickType_t period = MS_TO_TICKS( 50 );
 
    /* The lastWakeTime variable needs to be initialized with the current tick
        count. Note that this is the only time the variable is written to explicitly.
        After this assignment, lastWakeTime should be updated  within the
        atomTimerDelayUntil() function. 
   */
 
    lastWakeTime = atomTimeGet();
 
    /* Enter the loop that defines the task behavior. */
    while( 1 ) {  
        /* This task should execute every 50 milliseconds. Time is measured
            in ticks. lastWakeTime should be updated within the atomTimerDelayUntil()
            function so is not explicitly updated by the task.
        */
 
        /* Perform the periodic actions here. */     
 
        atomTimerDelayUntil(&lastWakeTime, period);	
    }
}

References

  1. Introduction to atomthreads
  2. atomthreads kernel Reference
  3. atomthreads Timer and system tick library
  4. atomthreads Documentation

Threads Assignment 5

  • Demonstrate that the scheduler always selects the highest Ready state task to run
    Write an atomPrioritySet(...) API function to change the priority of a task.
  • Create two tasks with different priorities.
    Neither task makes any API function calls that cause it to enter the Blocked state.
    • So both are in either Ready or Running state.
    • So the task with highest priority will always be the task selected by the scheduler to be in Running state
  • Expected Behavior
    1. Task 1 is created with the highest priority to be guaranteed to run first. Task 1 prints out a couple of strings before raising the priority of Task 2 to above its own priority.
    2. Task2 starts to run as it has the highest relative priority.
    3. Task 2 prints out a message before setting its own priority back to below that of Task 1.
    4. Task 1 is once again the highest priority task, so it starts to run and forcing Task 2 back into the Ready state.

References

  1. Introduction to atomthreads
  2. atomthreads kernel Reference
  3. atomthreads Documentation

Interrupt Assignment

  1. Create Task 1 as a continuous processing task.
    In Task 1, display "Task 1 is Running."
  2. Install an Interrupt handler for SW1 Button switch (GPIO PortF)
    There are two user push buttons on the EK-TM4c123GXL LaunchPad Board.
  3. Toggle Green LED whenever SW1 Key pressed

Code Snippet

/* Task 1 is continuous processing Task */
void Task1(uint32_t entry_param)
{
    while(1) {
        printf("%s", "Task1 is Running ...\n\r");
        for(volatile auto uint32_t ul = 0; ul < 0xffff; ul++ ){ ; }
    }
}
 
/* PortF Interrupt Service Routine */
void gpiof_isr(void)
{
    GPIO_PORTF_ICR_R = 0x10;     /* clear PF4 int */
 
    /* Must be called at the start of interrupt handler that may call an
       OS primitive and make a thread ready.  */                         
    atomIntEnter();   
 
    /* Process GPIO Port F Interrupt */
 
    /* Must be called at the end of interrupt handler that may call an
        OS primitive and make a thread ready. */
    atomIntExit(0);    
}

References

  1. Introduction to atomthreads
  2. atomthreads kernel Reference
  3. atomthreads Documentation

Semaphore Assignment

  1. Program Timer0A for 500ms periodic interrupt
    Timer programming How to ...
  2. Create two tasks as Task 1 and Task 2.
    Task 1 should be continuous processing task and display as "Task 1 is Running..."
    Task 2 will wait for the semaphore
  3. Toggle Blue LED if semaphore taken in the Task 2


Note: Semaphore objects must be initialised before use by calling atomSemCreate(). Once initialised atomSemGet() and atomSemPut() are used to decrement and increment the semaphore count respectively.

Code Snippets

/* Task 1 is continuous processing Task */
void Task1(uint32_t entry_param)
{
    while(1) {
        printf("%s", "Task1 is Running ...\n\r");
        for(volatile auto uint32_t ul = 0; ul < 0xffff; ul++ ){ ; }
    }
}
 
/* Task 2 waits for semaphore */
void Task2(uint32_t entry_param)
{
    while(1) {
 
        /* Wait for (Get) semaphore, If Yes, Toggle Blue LED */
 
    }
}
 
/* Timer0A Interrupt Service Routine */
void timer0a_isr((void)
{
    TIMER0_ICR_R = 0x01;            /* clear Timer0A timeout interrupt */
 
    atomIntEnter();
 
    /* Give (Put) Semaphore */
 
    atomIntExit(0);
}

References

  1. atomthreads kernel Reference
  2. atomthreads semaphore library
  3. atomthreads Documentation

Mutex Asssignment

  • A shared resource is a resource that can be used by more than one task. Each task should gain exclusive access to the shared resource to prevent data corruption. This is called mutual exclusion.
  • Shared I/O devices require the use of mutual exclusion; for example, a task might need exclusive access to a printer.
  • We will consider printf (uses UART) function as a shared resource because any task may call at any time to print some thing.
  • Create two tasks, Task1 and Task2 with equal priorities as continuous processing tasks.
    Task1 displays as "Task1 is running ..." and Task2 as "Task2 is running ..."
    Observe the output. Do you see any data corruption in the output?
  • Now, use mutual exclusion for printf function in both the Tasks.
    Observe the output

Note: Use atomMutexCreate(), atomMutexGet() and atomMutexPut() functions.

References

  1. atomthreads kernel Reference
  2. atomthreads Mutex Library
  3. atomthreads Documentation

Queue Assignment

There are two user push buttons on the EK-TM4C123GXL LaunchPad Board. Write a program to light the LEDs:

  • Green LED when SW1 is pressed.
  • Blue LED when SW2 is pressed.
  • Red LED when no key.

Howto:

  1. Import atomthreads Template Project into CCS workspace
  2. Rename the Project as atomthreads_queue_one
  3. Using Queue(s) send message whenever a key is pressed
  4. Read from the Queue and accordingly light the LEDs
  5. Implement key scanning task as periodic task
  6. Take care of key de-bouncing

References

  1. atomthreads kernel Reference
  2. atomthreads Queue library
  3. atomthreads Documentation