Início > Tutoriais > How to configure and use the BRTOS

How to configure and use the BRTOS

In this post we will present an introduction to the main settings of BRTOS and describe the basic steps to use it in a basic application. The information contained in this tutorial are compatible with version 1.4 and above of the BRTOS.

1. BRTOS settings

The amount of RAM required for the tasks will depend on the chosen CPU (RISC CPUs usually need more space in RAM, because they have more registers to be saved in the context), on the number of interrupts enabled in the system and on the needs of each task (local variables and function calls). For example, in a Coldfire V1 microcontroller with 3 interrupts enabled (using nesting interrupts enabled), we calculate the memory of a task as follows:

  • 72 bytes for the first interruption and 32 bytes for each of the next interruptions;
  • reserve space for local variables of the task. Do not forget to align the memory on the processor, ie, declare one byte followed by two words will occupy 8 bytes on a 32-bit processor.
  • reserve memory for call system services and functions. Nesting of functions requires more memory. For example, if a function is called from another function, the occupied amount of RAM will be proportional to the local variables, parameters and return address of both functions . The memory footprint for the functions depends on the number of parameters and local variables used by the function.

Before starting the development of an application you need to set some system parameters. These settings must be made ​​in the file BRTOSConfig.h.

  • The file BRTOSConfig.h has settings for define the amount of available memory, the system clock and the used microcontroller. Still, defines which events / services will be available for use (semaphore, mutex, mailbox and message queues). It will also determine the amount of possible instances for a particular service.

The file BRTOSConfig.h has the following structure:

// Define if simulation or DEBUG
#define DEBUG 1

// Define if whatchdog active
#define WATCHDOG 1

// Define if compute cpu load is active
#define COMPUTES_CPU_LOAD    1

// Define Number of Priorities

// Define the number of Task to be Installed
// must always be equal or higher to NumberOfInstalledTasks

// Define if OS Trace is active
#define OSTRACE 1

// Define if TimerHook function is active
#define TIMER_HOOK_EN 1

// Enables the OS semaphores
#define BRTOS_SEM_EN           1

// Enables the OS mutexes
#define BRTOS_MUTEX_EN         1

// Enables the OS mailboxes
#define BRTOS_MBOX_EN          1

// Enables the OS queues
#define BRTOS_QUEUE_EN         1

// Sets the maximum number of available semaphores (limits the memory allocation for semaphores)
#define BRTOS_MAX_SEM          4

// Sets the maximum number of available mutexes (limits the memory allocation for mutexes)
#define BRTOS_MAX_MUTEX        4

// Sets the maximum number of available mailboxes (limits the memory allocation for mailboxes)
#define BRTOS_MAX_MBOX         1

// Sets the maximum number of available queues (limits the memory allocation for queues)
#define BRTOS_MAX_QUEUE        1

// TickTimer Defines
#define configCPU_CLOCK_HZ          (INT32U)24000000
#define configTICK_RATE_HZ          (INT32U)1000
#define configTIMER_PRE_SCALER      0

// Stack Size of the Idle Task
#define IDLE_STACK_SIZE             (INT16U)128

/// Stack Defines
/// Coldfire with 8KB of RAM: 40 * 128 bytes = 5KB of Virtual Stack
#define HEAP_SIZE 40*128

// Queue heap defines
// 1KB of memory to the OS queues
#define QUEUE_HEAP_SIZE 8*128

// Others Defines
#define configMAX_TASK_NAME_LEN 16
#define configMAX_TASK_INSTALL 32
  • DEBUG is used on some platforms that have differences between the simulator and debugger. In this way, the code fits the desired condition. DEBUG = 1 indicates mode debugger / flash write.
  • WATCHDOG indicates whether the watchdog system is active. WATCHDOG = 1 indicates active watchdog.
  • COMPUTES_CPU_LOAD indicates whether the computes cpu load function is active. COMPUTES_CPU_LOAD = 1 indicates that cpu load will be computed.
  • NUMBER_OF_PRIORITIES sets the number of priorities supported by the system. The default is 32 priorities for 16 / 32bits microcontrollers or 16 priorities for 8-bit microcontrollers.
  • NUMBER_OF_TASKS indicates how many tasks can be installed in an application. The maximum value for this config is 31. This definition allows to allocate a smaller amount of memory for the tasks context. Use this feature to reduce the consumption of system memory when a small number of tasks is installed.
  • OSTRACE indicates whether the trace of the system is active or not. The system trace is used to monitor the behavior of the system.
  • TIMER_HOOK_EN indicates whether the timer anchor function is active. If so, you can run a small snippet of code from the tick timer interrupt. This is an important feature to implement tiny time checks, such as timeouts.
  • configCPU_CLOCK_HZ indicates the bus frequency used in the system in hertz.
  • configTICK_RATE_HZ indicates whether the timer anchor function is active. If so, you can run a small snippet of code from the tick timer interrupt. This is an important feature to implement tiny time checks, such as timeouts.defines the tick timer of the system (time stamp), ie, the time resolution of the RTOS time manager. Values ​​between 1 ms (1000 Hz) and 10 ms (100 Hz) are recommended. Never forget that the resolution of the time management is +/- 1 tick.
  • configTIMER_PRE_SCALER can be used in the microcontroller port to configure the hardware responsible for tick timer.
  • IDLE_STACK_SIZE determines the amount of memory allocated for the virtual stack of the Idle Task. The idle task will be installed in the BRTOSStart function, and the amount of memory used by this task will be allocated on the heap.
  • HEAP_SIZE determines the amount of memory allocated to the virtual stack of tasks (in bytes). Whenever a task is installed, the amount of memory used by the task will be allocated on this heap.
  • QUEUE_HEAP_SIZE determines the amount of memory allocated to the OS queues (in bytes). Whenever a queue is created, the amount of memory used by the queue will be allocated in this HEAP.
  • BRTOS_SEM_EN, BRTOS_MUTEX_EN, BRTOS_MBOX_EN e BRTOS_QUEUE_EN determine if the semaphore, mutex, mailbox and queue services, respectively, are or not available to the application. A value of 1 determines that the service will be available.
  • Os defines BRTOS_MAX_SEM, BRTOS_MAX_MUTEX, BRTOS_MAX_MBOX e BRTOS_MAX_QUEUE determine the maximum amount of instances that can be created for semaphores, mutexes, mailboxes and queues, respectively.

OBS: Starting with version 1.1 of BRTOS the higher the priority value associated with a task, the higher its priority in the system.

The file HAL.h contain port informations, the definition of nested interrupts and the used processor with the following structure (usually it is not necessary to change these settings):

// Supported processors
#define COLDFIRE_V1               1
#define HCS08                     2
#define MSP430                    3
#define ATMEGA                    4
#define PIC18                     5

/// Define the used processor
#define PROCESSOR               COLDFIRE_V1

/// Define the CPU type
#define OS_CPU_TYPE     INT32U

/// Define if the optimized scheduler will be used

/// Define if nesting interrupt is active
#define NESTING_INT 1

/// Define if its necessary to save status register / interrupt info
#if NESTING_INT == 1
  #define OS_SR_SAVE_VAR INT16U CPU_SR = 0;
  #define OS_SR_SAVE_VAR

/// Define stack growth direction
#define STACK_GROWTH 0            /// 1 -> down; 0-> up

/// Define CPU Stack Pointer Size
#define SP_SIZE 32

2. Starting an application

The boot sequence of the system should follow a well-defined order. The following steps should be taken:

  1. Initialization of the main registers of the microcontroller (system config)
  2. Start system services (if used)
  3. Start the internal hardware of the microcontroller
  4. Start the hardware external to the microcontroller
  5. Installation of the tasks
  6. Start the scheduler

The following is an example of initializing an application using the microcontroller Freescale Coldfire V1:

// Declares pointers to BRTOS control blocks
// Declare a queue pointer
BRTOS_Queue  *Serial;
// Declare a semaphore pointer
BRTOS_Sem    *Teclado;

// Declare a mailbox pointer
BRTOS_Mbox   *ConversorAD;

void main(void)
  /////      Initialization of the main cpu registers    /////

  /////      BRTOS initialization                        /////

  // Example of creating a queue
  // Create an event handler for a serial port
  // where the data managed by this event are in a circular buffer, called SerialPortBuffer
  if (OSQueueCreate(&SerialPortBuffer,512,&Serial) != ALLOC_EVENT_OK)
    // Oh Oh
    // It should not come in here !!!

  // Example of creating a semaphore
  // In this case, the semaphore is used to synchronize the keyboard interrupt with a task
  if (OSSemCreate(0,&Teclado) != ALLOC_EVENT_OK)
    // Oh Oh
    // It should not come in here !!!

  // Example of creating a mailbox
  // Should be used to wake a task that is waiting for a new value from the A/D converter
  if (OSMboxCreate(&ConversorAD,(INT16U *)0) != ALLOC_EVENT_OK)
    // Oh Oh
    // It should not come in here !!!

  /////      Hardware Initialization                     /////

  // Initializes I/O ports used in the application

  // Initializes the keyboard hardware

  // Sets/Initializes an A/D converter
  ADSetup(HighSpeed, ShortSampleTime, 12);

  // Sets/Initializes a PWM
  // PWM = Frequency 10Khz
  // Center Align
  // Channell 0 = Duty 40%
  // Polarity = Positive
  // Channell 1 = Duty 40%
  // Polarity = Negative

  /* Starts a serial port
     The resource priority ceiling is equal to 4 in this case (Note that this priority should be available and
     at least one level higher than the highest priority of the tasks that will use this resource.
     The protocol used in RTOS mutex changes the priority of the task that acquire the resource for this higher priority
     in order to avoid priority inversion and deadlocks. */

  /////      External Hardware Initialization            /////

  // Initialize a 16x2 LCD
  // LCD priority ceiling = 16

  /////      Startup of the tasks                        /////

  // Installs all tasks in the following format: (Address of the task, Task Name, Task Virtual Stack in bytes, Task Priority)

  // Each task must have a priority. The installation of a task in a busy priority will generate an exception

  if(InstallTask(&System_Uptime,"System Uptime",100,31) != OK)
    // Oh Oh
    // It should not come in here !!!

  if(InstallTask(&Task_2,"GLCD Handler",100,15) != OK)
    // Oh Oh
    // It should not come in here !!!

  if(InstallTask(&Task_3,"Serial Handler",200,3) != OK)
    // Oh Oh
    // It should not come in here !!!

  if(InstallTask(&Task_4,"Keyboard and PWM",100,5) != OK)
    // Oh Oh
    // It should not come in here !!!

  /////    Scheduler start                                /////
  /////    From now installed tasks begin to be executed  /////

  // Start Task Scheduler
  if(BRTOSStart() != OK)
    // Oh Oh
    // It should not come in here !!!

The application tasks should be created in the file tasks.c. The structure of a task is presented as follow:

// Task for the management of a RTC clock
void System_Uptime(void)
  // Task setup
  // This code will be executed only in the task initialization

  // Main loop of the task
  // A task is executed as a infinite loop in a foreground / background system
  // A task is usually implemented as a state machine or an infinite loop
  for (;;)
      // Task code

3. How to determine the priority associated with each task

Some general rules can be followed to determine task priorities in a preemptive operating system based on priorities. Some of them are:

  1. Tasks that manage I/O devices should have high priority. One reason is that these tasks should receive / process the data faster than the data source is sending new data. In a large operating system such as Linux and Windows, it is possible to note that the greater access to an I/O device (hard disk, for example), the greater the drop in system performance for other tasks. This is due to system services that manage I/Os are high priority.
  2. Some algorithms suggest that tasks that are performed quickly should have higher priority, while slower tasks receive lower priorities. Thus a slow task can be interrupted several times during its operation by higher priority tasks. The main algorithm of this line of thought is the Rate Monotonic (RM).
  3. Tasks that do not directly interfere with the operation of the system (update a display, for example) may have low priority.



  1. Nenhum comentário ainda.
  1. No trackbacks yet.

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do

Você está comentando utilizando sua conta Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: