Code optimization

ASCET-DEVELOPER generates highly portable, MISRA-C compliant source code, which can be readily consumed by the Arm Compiler. We will introduce some useful tips to control how ASCET-DEVELOPER generates code to best suit the Arm Architecture.

Further information on global options for optimizing ASCET-DEVELOPER can be found in the User Guide. Similarly, the Arm Compiler User Guide contains general documentation on writing optimized code.

Use structures for messages and global data

The use of many global variables is generally considered bad programming practice. Data encapsulation and abstraction with structures and helper functions are encouraged to improve maintainability, readability, and correctness. Avoiding the use of many global variables is also beneficial for model generated code.

The Arm processor is a load-store architecture, and therefore the data processing instructions cannot access global data directly. This type of variable is accessed with a read-modify-write strategy, and use a register containing a base address, with an optional offset, to load and store data to the core registers.

Grouping global registers together in memory so that a common base pointer can be used is a common optimization for Arm. First, a base address is loaded, and then a read from that base address, with or without an address offset. We recommend a single base address and reference to many variables as an offset from that address. The preference for this practice leads to the preference for the use of structures for global data.

Because most embedded systems have multiple task rates, and pre-emption is used in many cases, any task container must take protected copies of messages, passed as variables between tasks. ASCET-DEVELOPER supports several types of protected message copy, for example to take copies of all used messages under suspended interrupts. You can choose task rates and define the execution of task containers within an OS configuration App file for any project.

The original code for the modules uses individual messages. This means that an individual update or read must be performed for each message for a task before any execution occurs. Because each task can manipulate many messages, this procedure can become quite time-consuming.

Because each module in ASCET-DEVELOPER has a group of output interface messages defined in an Embedded Software Description Language formatted data interface file, these can easily be replaced with a single structure of messages.

The following code shows an example output interface message:

data interface SPInterface
{
	@symbol(“SP_Dig1Speed”)
	T_Speed_SP_Dig1Speed = 0x0;
	@symbol(“SP_Dig1Pin”)
	Boolean SP_Dig1Pin = false;
	@symbol(“SP_Dig1Duty”)
	T_DutyPercent_SP_Dig1Duty = 0x0;
…

The following code shows an example of replacement with a single structure:

	data interface SPInterface
	{
		SP_InterfaceData SP_If;
	}

A memcpy can take a local copy for use in a task container. Because the size of the structure is well known, the compiler can select the most efficient memcpy implementation from the compiler supplied C library.

Previous Next