Monday, 22 May 2017

Free RTOS Arduino foireann visage (Face Team)


Introduction
This blog discusses about using Free RTOS on Arduino which will be used for Nextion LCD screen. The reason mbed RTOS wasn't used is because the provided libraries for Nextion screen to operate is only on Arduino so it was hard to develop Nextion LCD library for Mbed in a given frame of time.

Free RTOS
Most operating systems appear to allow multiple programs or threads to execute at the same time. This is called multi-tasking. In reality, each processor core can only be running a single program at any given point in time. A part of the operating system called the scheduler is responsible for deciding which program to run when, and provides the illusion of simultaneous execution by rapidly switching between each program.

The scheduler in a Real Time Operating System (RTOS) is designed to provide a predictable (normally described as deterministic) execution pattern. This is particularly interesting for embedded systems, like the Arduino devices, as embedded systems often have real time requirements.

Traditional real time schedulers, such as the scheduler used in FreeRTOS, achieve determinism by allowing the user to assign a priority to each thread of execution. The scheduler then uses the priority to know which thread of execution to run next. In FreeRTOS, a thread of execution is called a Task.

Semaphore code:
------------------------------------------------------------------------------------------
#include 
#include   // add the FreeRTOS functions for Semaphores (or Flags).

// Declare a mutex Semaphore Handle which we will use to manage the Serial Port.
// It will be used to ensure only only one Task is accessing this resource at any time.
SemaphoreHandle_t xSerialSemaphore;


// define two tasks for Blink & AnalogRead
void TaskBlink( void *pvParameters );
void TaskAnalogRead( void *pvParameters );



// the setup function runs once when you press reset or power the board

void setup() {

  if ( xSerialSemaphore == NULL )  // Check to confirm that the Serial Semaphore has not already been created.
  {
    xSerialSemaphore = xSemaphoreCreateMutex();  // Create a mutex semaphore we will use to manage the Serial Port
    if ( ( xSerialSemaphore ) != NULL )
      xSemaphoreGive( ( xSerialSemaphore ) );  // Make the Serial Port available for use, by "Giving" the Semaphore.
  }

  // Now set up two tasks to run independently.
  xTaskCreate(
    TaskBlink
    ,  (const portCHAR *)"Blink"   // A name just for humans
    ,  128  // Stack size
    ,  NULL
    ,  1  // priority
    ,  NULL );



  xTaskCreate(
    TaskAnalogRead
    ,  (const portCHAR *) "AnalogRead"
    ,  128 // This stack size can be checked & adjusted by reading Highwater
    ,  NULL
    ,  2  // priority
    ,  NULL );

  // Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started.
}

void loop()
{

}

/*--------------------------------------------------*/
/*---------------------- Tasks ---------------------*/
/*--------------------------------------------------*/

void TaskBlink(void *pvParameters)  // This is a task.
{
  (void) pvParameters;

  // initialize digital pin 13 as an output.
  pinMode(13, OUTPUT);

  for (;;) // A Task shall never return or exit.
  {
     if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
    {
    digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
    Serial.println("red led on");
    vTaskDelay( 500 / portTICK_PERIOD_MS ); // wait for one second
    digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
    Serial.println("red led off");
    vTaskDelay( 500 / portTICK_PERIOD_MS ); // wait for one second
    xSemaphoreGive( xSerialSemaphore ); // Now free or "Give" the Serial Port for others  
    }
  }
}



void TaskAnalogRead(void *pvParameters)  // This is a task.
{
  (void) pvParameters;

  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);

  for (;;)
  {


    if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
    {

    int sensorValue = analogRead(A0);
    Serial.println(sensorValue);
    recieveData = sensorValue;
    vTaskDelay(100);  (15ms) in between reads for stability
    }
  }
}
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
The code shown above protects the serial port. It allows task 1 to  print out a value serially than hands the serial to second task so that the second task can print out the value. Then it was required to have semaphore in such way that first task reads in the value from Vision team and second task reads out the value so in order to do that we are required to protect the task. This was achieve by protecting semaphore and handing that semaphore as a key in between the tasks as shown below. This basically operates like a Mutex (Mutext is used to synchronize the execution of tasks by protecting the access to a shared resource).
-----------------------------------------------------------------------------------------------------------
#include 
#include   // add the FreeRTOS functions for Semaphores (or Flags).

// Declare a mutex Semaphore Handle which we will use to manage the Serial Port.
// It will be used to ensure only only one Task is accessing this resource at any time.
SemaphoreHandle_t xSemaphore;


// define two tasks for Blink & AnalogRead
void xRx( void *pvParameters );
void idTx( void *pvParameters );

int x = 0;
int id = 0;

// the setup function runs once when you press reset or power the board

void setup() {
  Serial.begin(9600);

  if ( xSemaphore == NULL )  // Check to confirm that the Serial Semaphore has not already been created.
  {
    xSemaphore = xSemaphoreCreateMutex();  // Create a mutex semaphore we will use to manage tasksh
    if ( ( xSemaphore ) != NULL )
      xSemaphoreGive( ( xSemaphore ) );  // Make the mutex available for use, by "Giving" the Semaphore.
  }

  // Now set up two tasks to run independently.
  xTaskCreate(
    xRx
    ,  (const portCHAR *)"Blink"   // A name just for humans
    ,  128  // Stack size
    ,  NULL
    ,  1  // priority
    ,  NULL );

  xTaskCreate(
    idTx
    ,  (const portCHAR *) "AnalogRead"
    ,  128 // This stack size can be checked & adjusted by reading Highwater
    ,  NULL
    ,  1  // priority
    ,  NULL );

  // Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started.
}

void loop()
{

}

/*--------------------------------------------------*/
/*---------------------- Tasks ---------------------*/
/*--------------------------------------------------*/


void xRx(void *pvParameters)  // This is a task.
{
  (void) pvParameters;

  for (;;) // A Task shall never return or exit.
  {
     if ( xSemaphoreTake( xSemaphore, ( TickType_t ) 5 ) == pdTRUE )
    {
      Serial.println("Semaphhore 1 lock"); 
      x = Serial.parseInt(); // read next valid integer from the serial buffer 
      Serial.println(x);

      Serial.println("Semaphhore 1 free"); 
      xSemaphoreGive( xSemaphore ); // Now free or "Give" to others 
      vTaskDelay(100);  // one tick delay (15ms) in between reads for stability
    }
  }
}


void idTx(void *pvParameters)  // This is a task.
{
  (void) pvParameters;

  for (;;) // A Task shall never return or exit.
  {
    if ( xSemaphoreTake( xSemaphore, ( TickType_t ) 5 ) == pdTRUE )
      {
          Serial.println("Semaphhore 2 lock"); 
          id = x;
          Serial.println(id);
      
          Serial.println("Semaphhore 2 free"); 
          xSemaphoreGive( xSemaphore ); // Now free or "Give" the Serial Port for others 
          vTaskDelay(100);  // one tick delay (15ms) in between reads for stability
      }  
  }
}
-------------------------------------------------------------------------------------------
Memory pool:
Memory pools are fixed-size block allocation used to allocate memory dynamically. The functions like Malloc, Calloc and realloc are used to allocate memory within the Memory pools.
Malloc function is used to declare the array of an memory how ever it does not initialises the array memory to 0 so this means some random data is in the memory, whereas when the memory is allocated using Calloc function than the allocated memory is initialised with 0's.
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
#include void Serialin (void); void SerialOut(void); void setup() {    Serial.begin(9600);    int *mpool = (int*)calloc(16,128);    int readout;  for (int i=0; i<= 16; i++){          mpool[i] = i+1;          Serial.println(mpool[i]);          delay(200);    }  free(mpool);
//mpool =NULL; 
 for (int j=0; j >= 16; j++){         readout = mpool[j];         Serial.println(readout);         delay(200);    } } void loop(){ }
-------------------------------------------------------------------------------------------
The above code shows simple allocation of the memory. It allocates array of 16, each array consist of 128 datatype size. The only problem that we encountered when using memory pools is that Free function does not free the memory location, that's why memory pools weren't used. 

No comments:

Post a Comment