TMS320 Compiler Traps and Tricks

By

This material refers to Code Composer Version 3.04 and might be somewhat outdated, but the compiler caveats could still be worth a look.  

The development environment Code Composer (CC, Version 3.04) is a great tool, but it has a few annoying quirks. Texas Instruments' Compiler 5.0 for TMS320C3x/4x produces code that comes close to hand-coded assembler. I discovered some strange features I considered bugs at first, but these all turned up to be the result of aggressive, yet correct, optimization, and my lack of respect for volatiles.

This page summarizes some things I found out when developing an ultrasound environment simulator with a tandem TMS320C4X.


Every time I invoke an incremental build, a full build is done, even if I changed only one module.

Check Project/Show Dependencies for a file name displayed red, i.e. reported missing. Whenever there is such a file, a full build will always be done. But why is a file reported missing, yet the project compiles without errors? Assume you have a header file that is shared between a Windows project and DSP project, and it includes a file that only makes sense for Windows.

#ifdef WINDOWS
#include <checks.h>
#endif

Checks.h is not on your DSP-path, because it should not be used anyway. Code Composer's dependency parser is a bit simple-minded and does not see the #ifdef, so it reports the file missing.

Workaround: Put a dummy file checks.h into your DSP path. Don't forget to add at least a comment blaming CC, people in future programming generations may not understands CC's subtleties.


A project build needs 3 minutes in Win95. On the same computer under Windows 2000, it crosses the line after 50 seconds.

This is a problem GO-DSP refuses to acknowledge, so it may be caused by my installation. Using Wintop, I found out that under Win95 CC_app always takes about 85% CPU time when the compiler is running; under Windows 2000, the same value is below 5%. It looks like the GUI never releases the time slice to let the compiler do the C-crunching. I also noticed that the 16-bit auxiliary program Ccvhrl3.exe is loaded under Win95, and not the 32-bit version cvrlh32.exe as under Win2k.

Workaround: use Windows 2000 or XP, it's anyway more fun. Or tell me how you did it under Win95.


I am confused by the many compiler options (SET=) and special paths I have to set in my autoexec.bat file or NT-like-environment when installing the Texas C-compiler.

Not a workaround, a solution: remove all SET/PATH statements needed for Code Composer, the compiler, assembler and for special library files of your board. Instead, define all options in Code Composer. Options not supported by checkboxes may be added manually into the edit field, CC is kind or clever enough to keep entries it has not created itself. (see next paragraph for an exception). Feel relieved when you project first compiles error-free in an unpolluted environment.


The function fabs gives an incorrect results when used with an integer argument.

Do you still rely on implicit conversion rules? I know, these things work in Borland and MS-compilers. Or at least, they give decent warning. Ooops ... maybe the function is right after all and you did not see the warning? Exactly: CC does not allow checkbox selection of the most important warning category, i.e. undeclared functions. And it hides quite a few intrinsic functions headers in <intrin.h>, where you won't expect it after so many ANSI-years.

Not a workaround, THIS IS AN ORDER  : Use the warning level -pw2 that reports undeclared functions. I believe this option has been added in compiler version 5.0. It is not supported in CC 3.04, but as other levels of -pw are supported, adding it manually in the compiler options confuses CC. So, despite what I said above about unpolluted environments, I have added this life-saver as the only option to my environment on startup.

SET C_OPTION=-pw2

Under Win2k, use Control Panel/System/Environment instead to add the option.

After recompiling, you will probably have to add a few #include <intrin.h>to your code, and possibly a few more missing headers will turn up. And, all of a sudden, some other unwanted features of your program disappear miraculously.


For TMS-C is an aggressively optimizing compiler...don't be caught volatile.

My code runs nicely in debug optimization, but plays by its own rules when optimized.

Well, if you have done embedded C-programming all your life, skip this. Windows programmers, like me, got used to never touch anything dangerous such as port addresses, by penalty of Dr. Watson or blue-screen. For all those: make sure to check your volatiles with embedded systems. When optimizing, Texas-C is really aggressive and removes all code accessing memory locations it believes full under its own control. If you get strange effects with optimization, try to add volatile to suspect variables.

Maybe you have written clever code that accesses contiguous external registers through structs; this approach gives highly efficient code, as addresses can be read and written with small offsets from a common base address in a register. In this case, make sure that you added the volatile to the struct-member that can be modified by the processor, e.g. read-only flags in DMA control.

If you occasionally are in masochistic moods: Try good old lint, e.g. Gimpel's PC-lint, or more recent splint, with the supplied settings for the TMS-compiler. It caught all my volatile-violations, hidden among 723 other violations, mostly in third-party code. After I had corrected 722 of them (I always leave one behind, so that the Gods won't be jealous, according Feynman Volume III, Quantum Mechanics, last page), my program worked. And I felt like Easter and Christmas falling on the same day, as we say in Germany.


After I introduced some conversions to IEEE-floats, some results were strange.

TMS can't handle IEEE-floats, so make sure once you converted to IEEE, you don't do any numerics with these. While you probably won't do it explicitly also check if some implicit conversion jump in. You may have to look at the generated assembler to make sure that the IEEE's aren't doubly converted to float or from float by compiler confusion.


Sure, you can debug Assembler with C4X, only Code Composer won't let you do it easily.

This is what the help file says:

Enable Source Level Debugging (-g):
(Available with TI assembler version 6.63 & higher for C2XX/C5X DSPs only) This option must be enabled to generate symbolic information for assembly source files. If this options is not selected, Code Composer will not be able to display Assembly-source when debugging

Because GO-DSP believes in this limitation, there is no checkbox for option -g with a C4X installed. However, you can add the switch -g manually in the edit field under Options/Assembler, to allow single-stepping through assembler source code. It works reasonably for macros, but fails with included assembler files (.include echo98.asm). Here is what Steve White of GO-DSP replied when I reported this:

Dieter,
I apologize for any inconvenience this may have caused. We will try to reproduce your results here and see if we are successful. We appreciate the below information as it may be that you have discovered something previously unknown by both TI and GO DSP.
Best Regards,
Steve White (GO-DSP)

No problem, Steve, if only things like this would turn up in your FAQ at some time.


printf (via JTAG) does not work.

Make sure that "Make global symbols static" on the linker page is NOT checked. Code Composer peeks at the symbols on loading and only opens the output page for printf and friends if it sees one of these functions.


Don't use explicit output path's for executables or intermediate assembler files.
Don't use non-default names for object output (e.g. o30 or o40).

This an annoying bug in Code Composer 3.04 and earlier that should have been corrected in a maintenance release. Whatever you try to do to keep your files nicely separated, there comes the point where CC does not find these in a following step, e.g. when auto-loading the program. I don't recall the details, since I gave up in an early phase. GO-DSP, this feature has not been tested carefully.


In a multiprocessor configuration, symbols with same name #define'd in different GEL files conflict.

In a system with two processors and two project, I had two GEL Files

/* FILT98.GEL Project Filt98, secondary Processor on TIM 44 */
#define Program "C:\\ECHO\\bin\\Filt98.out"
StartUp()
{
GEL_Load(Program);
}
/* ECHO98.GEL Project Echo98, Main Processor */
#define Program "C:\\ECHO\\bin\\Echo98.out"
StartUp()
{
GEL_Load(Program);
}

This does not work, and the error message is so confusing I needed some time to track down the source. CC seems to combine the two GEL-files, and believes that Program is defined twice. You must make #define's unique even in separate GELs used together, e.g.

#define FProgram "C:\\ECHO\\bin\\Filt98.out"
#define EProgram "C:\\ECHO\\bin\\Echo98.out"