ADSP 2181 Programming in C

Generally, the ADSP 21xx series DSP chips are programmed in assembly language for reasons of efficiency and performance. The assembly language syntax for these chips reminds one of a high-level language, which helps a lot in developing applications. Typically, someone with experience in wrtiting C programs will feel at home in this environment. As for complex programs, one has to keep things organized and orderly as you are in full control of the hardware and there are plenty of details to keep track of.

One often encounters an involved bit of code, like for example, crunching a floating-point formula, or perhaps needing double-precision math. For such cases, it would be nice to have access to a bit of C code. This prompted a little research and experimentation. It is assumed that you are familiar with the 2181 EZKIT and the tools that comes with the EVM. Also that you have access to G21, the C-compiler for the 21xx series. Incidentally, G21 is based on GNU GCC. The source code is available on the net, so it is technically possible to build a version of G21 for yourself. I will not get into how to do that, perhaps leave that for another experiment.

Note that the Analog Devices version of G21 will not run in a Windows Dos box, unless you have made extra efforts in dealing with memory managers needed for the DOS4GW environment. DOSBOX, a public-domain x86 emulator, however seem to work. Its a little slow, perhaps reminding one of a 486, but it works. I have been running G21 in DOSEMU under Linux without any problems. Even downloading code through the serial port works well under DOSEMU. If you installed the ADI 21xx C package, make sure to update the utilities with those supplied in the 2181 EZKIT package.

There is an application note, EE-14, that describes C example code, CTIP35, that is a C version of the Talk-Thru example to run on the 2181 EZKIT. Take a bit of time to study it as it contains valuable information on how to put a C program together. Unfortunately, the code from EE-14 does not build correctly under the version 5.1 C- tools that I have and needed modifications. Here is my version of CTIP35.ZIP. Of course, keep a copy of the ADSP-2100 Family C Tools and ADSP 2100 Family Assembler Tools & Simulator Manuals handy.

Reminder that when running a C environment, the system relies heavily on heap and stack management; the integrity of this environment needs to remain intact. The C run-time environment needs to be set up correctly and maintained all the time. Assuming we are going to use the C environment to perform a few once-in-a-while, difficult-to-progam tasks, definately not to be part of the main heavy-duty processing loops, keep a few simple rules in mind:

1. The following registers may be modified but must be restored: L0, L1, L5, L6, L7, M2, and M6.

2. The following registers are reserved and must not be used: L4 and M1.

3. As shown above, the C-environment uses I4, M4 for heap and stack management.

4. I2, L2, I3, L3, and M1 are used for CTIP35's CODEC autobuffering, so be careful.

5. Note the C run-time environment sets the MAC for integer arithmetic.

6. Watch out how a function's local variables are saved on the stack. Its not very efficient, so avoid if possible. Perhaps use of volatile DM storage is a solution.

The C run-time environment includes an interrupt dispatcher which relies on the DSP interrupt vectors. Note how this is done in 2181_HDR. You may also want to look at the included assembly-language listing for CTIP35. Note how an interrupt service routine is entered with a prologue and exited with an epilogue. For the "new_sample" ISR:

new_sample_:
{-----------------------------------------------------------------------}
{ FUNCTION PROLOGUE: }
mr1=toppcstack; { get return address }
si=m4;
m4=i4; { new frame ptr <= old stack ptr }
m5=-1;
dm(i4,m5)=si; { save old frame pointer }
dm(i4,m5)=mr1;{ save return address }
{ END FUNCTION PROLOGUE:}
{-----------------------------------------------------------------------}

===========> user code follows here. Note comments. <====================

{-----------------------------------------------------------------------}
{ FUNCTION EPILOGUE: }
i6=m4;
m5=-1;
si=dm(i6,m5); { old frame pointer}
mr1=dm(i6,m5); { return address }
i4=m4; { reset stack pointer }
i6=mr1;
m4=si; { reset frame pointer }
{ END FUNCTION EPILOGUE: new_sample }
jump (i6);
{-----------------------------------------------------------------------}

There are library functions that helps doing all this. Also look at using the assembly support functions (see "asm_sprt.h").

To my Home Page