Inspirel banner

YAMI4 with TI-RTOS on EK-TM4C1294XL

YAMI4 is a messaging solution for distributed systems.

TI-RTOS is a real time operating system, dedicated for use with Texas Instruments processors and microcontrollers. TI-RTOS includes the NDK (Network Development Kit) as its integral part.

EK-TM4C1294XL development board is a board from TI that allows to prototype IoT products and looks like here:

EK-TM4C1294XL board

Last but not least, the Code Composer Studio is a development environment, based on the Eclipse framework, dedicated for use with TI products.

This article describes their integration, the steps taken to build and run the example program and the concerns that need to be taken into account when developing similar applications.

Note: there is a sibling article devoted to the MSP-EXP432E401Y board - even though both boards seem to be similar in many aspects, their SDKs are different and they represent different product families.

Article outline:

General idea

IDE workspace and options

A bit of manual work

Running the subscription example

API changes in YAMI4

General idea

The Code Composer Studio facilitates development of user applications by providing a wide range of example programs for each supported hardware platform - these example programs can be used as starting points for custom programs. The YAMI4 libraries can be added to the CCS workspace and integrated with already existing projects. The two YAMI4 components are the core library, which provides basic messaging services, and the general-purpose C++ library, which supports higher-level messaging patterns on top of the core library.
The idea presented here relies on the empty example project as a starting point, so that all settings related to networking can be seen and understood explicitly. The empty example can be installed from the Resource Explorer:

Empty example from the Resource Explorer

In order to avoid conflicts with accidental re-installation of this example, the empty project can be renamed - this article uses the name myProgram as the actual application name after such name change.

Even though this choice is purely arbitrary, the following relies on the assumption that the YAMI4 distribution package was unpacked directly in the workspace directory - that is, as a sibling to the myProgram project directory. The YAMI4 package contains two projects already prepared for import into CCS:

These two projects should be imported into the CCS workspace:

Basic workspace layout

Above, YAMI4-TivaC-core and YAMI4-TivaC-cpp are library projects and myProgram is the actual application program that directly relies on the general-purpose C++ library, as well as on TI-RTOS and NDK, by means of its project product dependencies (these are automatically imported from the original empty example).

IDE workspace and options

Once the project skeleton is imported and put together with the YAMI4 libraries in a single workspace, the more detailed look at the application project structure is:

TivaC project - detailed view

There are multiple files in the myProgram project, but the ones that are of direct interest to the developer are:

The application relies on both YAMI4 libraries and even though it is not necessary, this is clearly expressed as project dependencies, so that modifications in any of the parts are always properly synchronized and taken into account in final builds.

Having the workspace and file structure in place, the following options need to be considered to properly tie together all involved projects.

For the YAMI4 Core library:

YAMI4 Core project settings 1

The device setting above just reflects the choice of target device. All options here have default values.

YAMI4 Core project settings 2

The setting above relates to the include paths and in addition to the first two, which are contributed by the YAMI4 core library itself, the remaining ones refer to the TI-RTOS system and its components. The version numbers in these paths reflect the actual packages that were automatically installed by CCS together with the original example program and are likely to change with future SDK updates.

YAMI4 Core project settings 3

The YAMI4_WITH_TIRTOS pre-processor symbol needs to be defined for both YAMI4 libraries and for the final application as well.

YAMI4 Core project settings 4

The language settings - the YAMI4 Core library does not use exceptions or RTTI, but calls back into higher levels that do, so they need to be enabled (this should be also set for the other projects).

With all the options set appropriately, the YAMI4 Core library project should involve all these source files from the YAMI4 distribution package:

Settings for the YAMI4-TivaC-cpp library project should be similar, except for the include directories:

YAMI4 C++ project settings 2

Similarly to the core part, the YAMI4 C++ library project should refer to the following sources from the YAMI4 distribution package:

Finally, for the actual myProgram application, include paths and the set of dependent library files:

Actual project settings 2
Actual project settings 3

A bit of manual work

Apart from the project settings described above, two files need to be modified in order to properly integrate together all components.

The empty.cfg file needs to be modified slightly in order to enable networking components of TI-RTOS and to ensure that enough resources are available for the final program. In particular, the heap size needs to be increased to allow meaningful messaging (the default size of 1024 is certainly too small):

BIOS.heapSize = 32768;

In addition to the above modification, the following lines need to be added at the end of the config file:

var Ndk       = xdc.loadPackage('ti.ndk.config');
var Global    = xdc.useModule('ti.ndk.config.Global');
var Ip        = xdc.useModule('ti.ndk.config.Ip');
var Udp       = xdc.useModule('ti.ndk.config.Udp');
var Tcp       = xdc.useModule('ti.ndk.config.Tcp');

Global.IPv6 = false;
Global.stackLibType = Global.MIN;
Global.networkOpenHook = "&netOpenHook";

/* automatically call fdOpen/CloseSession for our sockets Task */
Global.autoOpenCloseFD = true;

Global.pktSizeFrameBuf = 1536;
Global.pktNumFrameBufs = 10;
Global.memRawPageCount = 6;
Global.ndkThreadStackSize = 1536;
Global.lowTaskStackSize = 1024;
Global.normTaskStackSize = 1024;
Global.highTaskStackSize = 1024;
Tcp.transmitBufSize = 1024;
Tcp.receiveBufSize = 1024;
Ip.autoIp = false;
Ip.address = "192.168.11.112";
Ip.mask = "255.255.255.0";
Ip.socketConnectTimeout = 5;

The values above provide a reasonable starting point for further tuning. The IP address and mask relate to the particular networking environment where the program is deployed. These settings do not have to be static, NDK can also obtain them from DHCP.

The main function (in the empty.c file) initializes the hardware and software components according to the config settings and starts an actual application task in the network set-up hook to ensure that the program operation is performed with the network adapter already in the proper state. The name of the hook, netOpenHook was actually selected above in the configuration file. The main function and the network hook can be written like here:

#define TASKSTACKSIZE 2048
Task_Struct taskStruct;
Char taskStack[TASKSTACKSIZE];

Void run_publisher(UArg arg0, UArg arg1);

void netOpenHook()
{
    Task_Params taskParams;

    Task_Params_init(&taskParams);
    taskParams.stackSize = TASKSTACKSIZE;
    taskParams.stack = &taskStack;
    Task_construct(&taskStruct, &run_publisher, &taskParams, NULL);
}

int main(void)
{
    Board_initGeneral();
    Board_initGPIO();
    Board_initEMAC();

    BIOS_start();

    return (0);
}

Above, the run_publisher function is declared and then called as a task function from netOpenHook, which is called automatically when the network is set up. The run_publisher function is implemented in a separate file publisher.cpp, included in the set of YAMI4 examples.

Running the subscription example

The subscription example is the most elaborate in the YAMI4 distribution package, because the publisher program acts both as a server (accepts subscription requests from clients) and as a client (sends a stream of data updates to subscribers).

The following screenshot (click for full size) demonstrates the publisher program running on the EK-TM4C1294XL board, with two subscribers launched on the host computer - they are started several seconds after the program starts on the board. As can be seen, values generated by the board are properly delivered to both subscriber programs.

Publisher screenshot

Note that in the background, in the central pane of the CCS environment, a fragment of publisher.cpp file is visible with the loop that actually is responsible for periodic generation of new published values. This code is very high-level, with a single line actually devoted to publishing the value to all currently active subscribers - yet it is all that is needed and the YAMI4, TI-RTOS and NDK do the rest.

API changes in YAMI4

One of the main design goals of YAMI4 is to be composable and non-intrusive with regard to its application in the target program. These goals mean in particular that YAMI4 should not hijack the environment and it should not assume that it is the only user of some resource, like a memory space or a network stack. These goals are straightforward on a POSIX or Windows system, where system resources are managed outside of the user code, but in RTOS it is the user code that decides when and how the environment is set up. In order not to interfere with the policies of the user code:

This approach allows the user retain complete control over when and how these critical system resources are created, which includes decisions like whether resources are allocated statically or dynamically or what should be the task priorities or their stack sizes. See the example programs (like the complete content of the publisher.cpp presented above) to check how the user code can provide the necessary resources to the YAMI4 agent.

Go to the YAMI4 homepage to learn more about the project and to find its distribution packages.