This post is a short tutorial on using RapidiTTy™ Builder to develop a simple — yet complete — embedded system. In order to keep the tutorial to a reasonable length, I’m assuming that you already have a working installation of RapidiTTy™ Builder. A more complete version of this tutorial, including installation instructions, is available on our downloads page.
Suppose we want to develop an embedded application to perform some simple data acquisition. We might want to receive analogue data as input, process it in some way and then send the result to a connected desktop computer. At a high level, developing such an application with RapidiTTy™ Builder is easy — we can use the TTE Builder™ engine to produce and configure the following components:
We can start this process by opening RapidiTTy™ Builder. The first time we do this, we are presented with a dialog asking us to choose a “workspace”, shown here:
The workspace is simply the directory under which all current projects are stored. For this tutorial, we will be using “D:\Workspace”, but any value may be used as long as you know where the projects are being stored for future reference.
We can create a new RapidiTTy™ Builder project by selecting “New → RapidiTTy Project” from the File menu (or by clicking the new project button on the left of the toolbar). This results in the new project dialog, shown here:
In this case, we have chosen to name the project “ADC_PC_Interface”. This name will also be the default name of the compiled binary that is created, should it be required outside of RapidiTTy™ Builder.
Once we have selected an appropriate name for the project, we are asked to choose and configure the target platform. This includes selecting the development board in use, deciding on using RAM or flash memory for code storage and specifying the crystal frequency that we are using.
Next, we are prompted to configure the Phase Locked Loop (PLL) settings to achieve the desired internal frequency, but the default settings will suffice for the purposes of this tutorial. We can now move on to selecting a starting point for the project.
When asked to choose a starting point for the project, we have the choice of starting a blank project, using one of the supplied samples, or generating a new project with the TTE Builder™ engine. We will use the TTE Builder™ engine in this tutorial, which results in the dialog shown here:
There we can see the components we have selected for the system. A “Heartbeat LED” is a good starting point for a project, as it simply flashes an LED on and off with a given frequency. This allows us to see clearly that our hardware is working and has been programmed correctly, as well as letting us know that the PLL configuration was successful.
The remaining tasks are those we discussed previously. The input is gathered through the development board’s built-in ADC, after selecting the appropriate ADC task we can configure it as shown here:
Of particular note here is that we have chosen to execute the task (gather data from the ADC) at one second intervals (shown as a 1000 ms task period in the dialog), starting as soon as the scheduler starts running (an initial delay of zero) and depositing the ADC value into a global variable for use elsewhere. We have also left the ADC pin as the default, which is valid for the Olimex LPC-P2129 development board.
Next, we will select and configure the user defined task. As the purpose of this task is to process the ADC data and then pass it along to the output task, we have chosen a one second task period again, to match the ADC task:

Also of note here is that we have chosen to start the user defined task (which we’ve named “Process_Data” here) 10 ticks after the scheduler begins. By default the scheduler is operating with a one millisecond tick interval, so this means that the Process_Data task will always execute 10 ms after the ADC_Update task has run.
Unlike the ADC and user defined task components, selecting the UART component results in the generation of two tasks. The first is the character update task, which executes every 10 ms and simply sends a single character from the buffer to the computer over the RS-232 connection.
The second task is the display update task, which corresponds to the function “UART_Display_Update” in the generated source-code. We have configured this to execute every second, starting at 20 ms so that it will execute after our own user-defined Process_Data task:

When the project has finished being generated, RapidiTTy™ Builder should display the project properties view. This view can be accessed at any time by opening the “.project” file in the navigator view (which is on the left by default).
The properties view is used to alter many of the available project-wide settings. From here, we can alter the component configuration settings, as well as building the project and uploading the code to a development board. Whenever changes are made in this view, it must be ‘saved’ before the changes will be applied to the remainder of the project. Changes made to the configuration may alter the relevant generated source files — this saving mechanism allows us to experiment with the configuration options in a temporary way, without affecting the code.
The project properties allows access to functionality that affects the project as a whole, such as the TTE Builder™ configuration settings. We can change any of the settings that were selected in earlier from here, then simply save the project properties file to apply the changes to the rest of the project:

To the left of the software specifications area shown above, we find the “Build and Test” area as shown below. Here we can rebuild the entire project, upload it to a development board, or start debugging. These actions are also available from the toolbar, shown as buttons sharing the same icons as shown here:

When we have uploaded the code, we can see the initial output of the UART task by opening the serial console in RapidiTTy™ Builder. We are using COM4 and a baud rate of 9600 (as shown below) — you must select these after first entering the RS232 view:
Note that the UART_Display_Update task is currently empty, so there is no output after the initialisation message (which can be removed from the initialisation function if it is not wanted). As this first message is only displayed once, you may have to reset the development board after switching to the RS232 view in order to see it.
A project that simply outputs the string “UART Initialization” at start-up is not overly useful. Nor does it accomplish our goal of processing the ADC data and outputting it over RS-232. In order to do this, we must understand how the tasks in the system can communicate with each other.
We want to access the output of the ADC in order to process it as part of the Process_Data task. As discussed previously, we chose to store the ADC output in a variable. This variable can be found, surprisingly, in the “adc.c” file. If we open that source file, we can see that the global variable “adc_reading” is used to store the entire 10-bit ADC range as an integer (whose value will vary from 0 to 1023).
We can access this global variable from the Process_Data task simply by declaring it as an external, more specifically by adding “extern uint32_t adc_reading;” near to the top of the file. Sharing a global variable between tasks in this way is perfectly safe, as the TTCos scheduler is co-operative and will never allow one task to pre-empt another:
// Output from the Process_Data_Update, used by UART_Display_Update. uint32_t processed_data; // Input to Process_Data_Update, from ADC_Update. extern uint32_t adc_reading;
This is a general pattern for inter-task communication in co-operatively scheduled systems — we can simply declare global variables for the tasks that own them and access them elsewhere. For example, the source-code above shows the variables used for both input and output by the Process_Data task, to be added at the top of the Process_Data.c file.
Each task initially consists of just two functions — an initialisation function (generally named after the task and ending in “_Init” in the generated code) and an update function (similarly named and ending in “_Update”). The initialisation function is called just once for each task when the system is first powered up or reset, but the update function is first called at the task’s initial delay and then again regularly with the specified update period.
This update function is where the task performs most, if not all, of its necessary work — for example, the Process_Data_Update function may be altered to scale the ADC reading to the range 0 to 100, making it a percentage:
void Process_Data_Update (void) { // Used for debugging with RapidiTTy. T0TCR = 0; T0TCR = 1; // Scale ADC reading to a percentage. processed_data = (adc_reading * 100) / 1023; // Used for debugging with RapidiTTy. T0TCR = 0; T0TCR = 1; }
The start and end of each generated update function contains two cryptic-looking lines of code that are intended for use as debugging aids with RapidiTTy™ Builder. In fact, all these lines of code actually do is stop and immediately start the timer, which has no real impact on the operation of tasks. However, it does provide with hooks into the first and last operations of the task, which enables us to do accurate timing analysis.
These lines of code should not be removed and should always be the first and last in the update function. We cannot add these lines of code anywhere else in the function either, as this would invalidate the results of any timing analysis that is carried out on the task.
Now that we have processed the data into the desired form of a percentage, we need to alter the UART task’s update function to output the value. The source-code below shows one way of doing this, using the C standard library’s “snprintf” function to convert the integer value to a string and the UART library function “UART1_O_Write_String_To_Buffer” to output the string over the RS-232 link:
// Included for the standard snprintf function. #include <stdio.h> // Input to UART_Display_Update, from Process_Data_Update. extern uint32_t processed_data; void UART_Display_Update(void) { // Used for debugging with RapidiTTy. T0TCR = 0; T0TCR = 1; // Display the ADC value as a percentage. char Disp_Str[20]; snprintf(Disp_Str, 20, "\rADC Reading: %d%% ", processed_data); // Ensure the string ends with zero for safety. Disp_Str[19] = 0; // Write the string to the output buffer. UART1_O_Write_String_To_Buffer(Disp_Str); // Used for debugging with RapidiTTy. T0TCR = 0; T0TCR = 1; }
As we can see below, the system output is exactly as we would expect and the system appears to work as originally specified:
Unfortunately, although the system appears to work correctly, we may still have a problem with using standard library functions such as snprintf. They are very complex and so we cannot say for certain exactly how long the task as a whole will take to complete. This is a problem for us, as our task’s update function must not exceed the chosen scheduler tick interval, or the timing of the entire system will be thrown off. What we need then, is a way to verify that this task will complete within the one millisecond tick interval that we chose when creating the project.
RapidiTTy™ Builder can gather timing statistics for us, allowing us to verify the timing of tasks as well as the system as a whole. To start this process, we simply select “Debug…” from the toolbar and use the statistics tab of the resulting debug dialog:
After selecting the tasks that we want to collect statistics for, as well as deciding how many times should allow each task to execute, we can simply press the “Debug” button to start the whole process. RapidiTTy™ Builder then gathers the timing data automatically and, when done, will present the results as shown here:
We can see that the UART_Display_Update function executes in less than half a millisecond. This is not the whole story — the UART_Display_Update function must occasionally execute within the same tick interval as the UART1_O_Update function, so these should have a combined execution time of less than one millisecond. Fortunately, we can see from the timing statistics that this is true, even when looking at the worst-case results.
Now that we have completed (and to some extent verified) our first project, where can we go from here?
If you have questions or comments about this tutorial or RapidiTTy™ Builder in general, please feel free to share them in the discussion forum. Alternatively, you can contact us directly.